<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>索修远のBlog</title>
  
  <subtitle>路漫漫其修远兮，吾将上下而求索。</subtitle>
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2024-08-12T14:30:59.785Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>索修远</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>centos7 yum报错：cannot find a valid baseurl for repo:base/7/x86_64的解决方案</title>
    <link href="http://example.com/posts/e49a5a03.html"/>
    <id>http://example.com/posts/e49a5a03.html</id>
    <published>2024-08-09T11:19:31.000Z</published>
    <updated>2024-08-12T14:30:59.785Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h4 id="已解决centos7-yum报错：cannot-find-a-valid-baseurl-for-repo-base-7-x86-64的解决方案"><a href="#已解决centos7-yum报错：cannot-find-a-valid-baseurl-for-repo-base-7-x86-64的解决方案" class="headerlink" title="已解决centos7 yum报错：cannot find a valid baseurl for repo:base&#x2F;7&#x2F;x86_64的解决方案"></a>已解决centos7 yum报错：cannot find a valid baseurl for repo:base&#x2F;7&#x2F;x86_64的解决方案</h4><h2 id="报错说明"><a href="#报错说明" class="headerlink" title="报错说明"></a>报错说明</h2><p>出现<code>cannot find a valid baseurl for repo:base/7/x86_64</code>错误通常是由于YUM仓库源无法找到或无法访问，导致YUM无法正常工作。这种情况常见于<a href="https://so.csdn.net/so/search?q=CentOS&spm=1001.2101.3001.7020">CentOS</a> 7系统。解决这个问题需要检查几个方面，如网络连接、DNS设置和YUM仓库源配置。以下是详细的排查解决方法。</p><h2 id="方法一：检查网络连接"><a href="#方法一：检查网络连接" class="headerlink" title="方法一：检查网络连接"></a>方法一：检查网络连接</h2><p>首先，确保你的系统可以连接到互联网。这很重要，因为YUM需要访问远程仓库来下载软件包。</p><h3 id="检查网络连接"><a href="#检查网络连接" class="headerlink" title="检查网络连接"></a>检查网络连接</h3><p>可以通过以下命令检查系统是否能访问外部网站：</p><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">ping -c 4 google.com</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>如果不能ping通，可能是网络配置问题。你需要确保网络连接正常，可能需要重新启动网络服务：</p><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">sudo</span> systemctl restart network</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="方法二：检查DNS设置"><a href="#方法二：检查DNS设置" class="headerlink" title="方法二：检查DNS设置"></a>方法二：检查DNS设置</h2><p>如果你的网络连接正常但依然不能访问仓库，可能是DNS问题。</p><h3 id="更新DNS配置"><a href="#更新DNS配置" class="headerlink" title="更新DNS配置"></a>更新DNS配置</h3><p>编辑<code>/etc/resolv.conf</code>文件，确保其中包含有效的DNS服务器，例如Google的公共DNS：</p><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">sudo</span> nano /etc/resolv.conf</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></pre></td><td class="code"><pre><span class="line">nameserver 8.8.8.8</span><br><span class="line">nameserver 8.8.4.4</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>保存文件并退出。</p><h3 id="检查是否能解析域名"><a href="#检查是否能解析域名" class="headerlink" title="检查是否能解析域名"></a>检查是否能解析域名</h3><p>再次检查系统是否能解析域名：</p><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">ping -c 4 google.com</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="方法三：检查YUM仓库配置"><a href="#方法三：检查YUM仓库配置" class="headerlink" title="方法三：检查YUM仓库配置"></a>方法三：检查YUM仓库配置</h2><p>如果网络连接和DNS设置都正常，可能是YUM仓库配置有问题，需要检查并更新YUM仓库源。</p><h3 id="更新YUM仓库源"><a href="#更新YUM仓库源" class="headerlink" title="更新YUM仓库源"></a>更新YUM仓库源</h3><ol><li><strong>备份现有的YUM配置文件</strong>：</li></ol><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">sudo</span> <span class="built_in">cp</span> -r /etc/yum.repos.d /etc/yum.repos.d.backup</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol><li><strong>编辑或替换仓库配置文件</strong></li></ol><p>检查<code>/etc/yum.repos.d/CentOS-Base.repo</code>文件。确保baseurl和gpgcheck配置正确。你可以手动编辑这个文件，或者更换为可靠的YUM仓库源。</p><h4 id="示例：使用官方CentOS镜像配置"><a href="#示例：使用官方CentOS镜像配置" class="headerlink" title="示例：使用官方CentOS镜像配置"></a>示例：使用官方CentOS镜像配置</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">sudo</span> nano /etc/yum.repos.d/CentOS-Base.repo</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>将内容替换为以下内容：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><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="section">[base]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Base</span><br><span class="line"><span class="attr">baseurl</span>=http://mirror.centos.org/centos/<span class="variable">$releasever</span>/os/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br><span class="line"><span class="section">[updates]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Updates</span><br><span class="line"><span class="attr">baseurl</span>=http://mirror.centos.org/centos/<span class="variable">$releasever</span>/updates/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br><span class="line"><span class="section">[extras]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Extras</span><br><span class="line"><span class="attr">baseurl</span>=http://mirror.centos.org/centos/<span class="variable">$releasever</span>/extras/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>保存文件并退出。</p><h3 id="清理YUM缓存并重建缓存"><a href="#清理YUM缓存并重建缓存" class="headerlink" title="清理YUM缓存并重建缓存"></a>清理YUM缓存并重建缓存</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"><span class="built_in">sudo</span> yum clean all</span><br><span class="line"><span class="built_in">sudo</span> yum makecache</span><br><span class="line"><span class="built_in">sudo</span> yum update</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="方法四：使用阿里云或其他国内镜像源"><a href="#方法四：使用阿里云或其他国内镜像源" class="headerlink" title="方法四：使用阿里云或其他国内镜像源"></a>方法四：使用阿里云或其他国内镜像源</h2><p>如果你在国内，使用国内的镜像源通常可以提供更快和更稳定的访问速度。以下是如何配置阿里云镜像源：</p><ol><li><strong>更新YUM仓库源为阿里云镜像源</strong>：</li></ol><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">sudo</span> nano /etc/yum.repos.d/CentOS-Base.repo</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>将内容替换为以下内容：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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="section">[base]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Base - mirrors.aliyun.com</span><br><span class="line"><span class="attr">baseurl</span>=http://mirrors.aliyun.com/centos/<span class="variable">$releasever</span>/os/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br><span class="line"><span class="section">[updates]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Updates - mirrors.aliyun.com</span><br><span class="line"><span class="attr">baseurl</span>=http://mirrors.aliyun.com/centos/<span class="variable">$releasever</span>/updates/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br><span class="line"><span class="section">[extras]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Extras - mirrors.aliyun.com</span><br><span class="line"><span class="attr">baseurl</span>=http://mirrors.aliyun.com/centos/<span class="variable">$releasever</span>/extras/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br><span class="line"><span class="section">[centosplus]</span></span><br><span class="line"><span class="attr">name</span>=CentOS-<span class="variable">$releasever</span> - Plus - mirrors.aliyun.com</span><br><span class="line"><span class="attr">baseurl</span>=http://mirrors.aliyun.com/centos/<span class="variable">$releasever</span>/centosplus/<span class="variable">$basearch</span>/</span><br><span class="line"><span class="attr">gpgcheck</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">enabled</span>=<span class="number">0</span></span><br><span class="line"><span class="attr">gpgkey</span>=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-<span class="number">7</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>保存文件并退出。</p><h3 id="清理并重建缓存"><a href="#清理并重建缓存" class="headerlink" title="清理并重建缓存"></a>清理并重建缓存</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"><span class="built_in">sudo</span> yum clean all</span><br><span class="line"><span class="built_in">sudo</span> yum makecache</span><br><span class="line"><span class="built_in">sudo</span> yum update</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><code>cannot find a valid baseurl for repo:base/7/x86_64</code>错误通常是由于<a href="https://so.csdn.net/so/search?q=%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E9%97%AE%E9%A2%98&spm=1001.2101.3001.7020">网络连接问题</a>、DNS设置问题或YUM仓库配置问题引起的。通过检查并修复网络连接、更新DNS设置、修改YUM仓库配置或使用可靠的镜像源，如阿里云镜像源，可以解决这个问题。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
    <category term="bug" scheme="http://example.com/tags/bug/"/>
    
  </entry>
  
  <entry>
    <title>RBAC权限模型</title>
    <link href="http://example.com/posts/a3597c8c.html"/>
    <id>http://example.com/posts/a3597c8c.html</id>
    <published>2024-08-05T09:13:54.000Z</published>
    <updated>2024-08-05T11:45:20.562Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="RABC权限模型"><a href="#RABC权限模型" class="headerlink" title="RABC权限模型"></a>RABC权限模型</h1><h2 id="一、RBAC权限模型"><a href="#一、RBAC权限模型" class="headerlink" title="一、RBAC权限模型"></a>一、RBAC权限模型</h2><p>​RBAC的基本思想是，对系统操作的各种权限不是直接授予具体的用户，而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。一旦用户被分配了适当的角色后，该用户就拥有此角色的所有操作权限。这样做的好处是，不必在每次创建用户时都进行分配权限的操作，只要分配用户相应的角色即可，而且角色的权限变更比用户的权限变更要少得多，这样将简化用户的权限管理，减少系统的开销。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805171830.png"></p><p>RBAC模型中的权限是由模块和行为合并在一起而产生的，在MySQL中，有模块表（tb_module）<br>和行为表（tb_action），这两张表的记录合并在一起就行程了权限记录，保存在权限表（tb_permission）中。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805171911.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805172424.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805172455.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805172527.png"></p><p>​现在知道了权限记录是怎么来的，下面我们看看怎么把权限关联到角色中。传统一点的做法是创建一个交叉表，记录角色拥有什么权限。但是现在MySQL5.7之后引入了JSON数据类型，所以我在角色表（tb_role）中设置的permissions字段，类型是JSON格式的。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805172927.png"></p><p>​到目前为止，JSON类型已经支持索引机制，所以我们不用担心存放在JSON字段中的数据检索速度慢了。MySQL为JSON类型配备了很多函数，我们可以很方便的读写JSON字段中的数据。</p><p>​接下来我们看看角色是怎么关联到用户的，其实我在用户表（tb_user）上面设置role字段，类型依旧是JSON的。这样我就可以把多个角色关联到某个用户身上了。</p><h2 id="二、前后端权限验证"><a href="#二、前后端权限验证" class="headerlink" title="二、前后端权限验证"></a>二、前后端权限验证</h2><p>​关于权限验证的工作，前端要做，后端也要做。后端的权限验证还好说，Shiro框架可以做这个事情。但是移动端没有权限验证框架，所以需要我们自己封装函数来验证权限。每个页面在渲染的时候，先判断用户拥有什么权限，然后根据权限控制渲染的内容。比如说普通员工没有添加新员工的权限，所以界面上就不能出现添加按钮。</p><p>​移动端做权限判断的前提是必须有当前用户的权限列表，这个权限列表是用户登陆成功或者注册成功，后端Java项目返回给移动端的，移动端保存到本地Storage里面。</p><h2 id="三、如何查询用户的权限列表？"><a href="#三、如何查询用户的权限列表？" class="headerlink" title="三、如何查询用户的权限列表？"></a>三、如何查询用户的权限列表？</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></pre></td><td class="code"><pre><span class="line">SELECT JSON_ARRAY(10,20,30)</span><br><span class="line">-- 创建一个json【10,20,30】数组</span><br><span class="line"></span><br><span class="line">SELECT JSON_CONTAINS(JSON_ARRAY(10,20,30), &quot;100&quot;)</span><br><span class="line">-- 判断100是否在json数组里</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></pre></td><td class="code"><pre><span class="line">-- 查询用户的权限列表</span><br><span class="line">SELECT DISTINCT p.permissin</span><br><span class="line">FROM tb_user u</span><br><span class="line">JOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))</span><br><span class="line">JOIN tb_permission p ON JSON_CONTAINS(r.permissions, CAST(p.id AS CHAR)) WHERE u.id=用户id AND u.status=1;</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></pre></td><td class="code"><pre><span class="line">&lt;select id=&quot;searchUserPermissions&quot; parameterType=&quot;int&quot; resultType=&quot;String&quot;&gt;</span><br><span class="line">  SELECT DISTINCT p.permission_name</span><br><span class="line">  FROM tb_user u</span><br><span class="line">         JOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))</span><br><span class="line">         JOIN tb_permission p ON JSON_CONTAINS(r.permissions, CAST(p.id AS CHAR))</span><br><span class="line">  WHERE u.id=#&#123;userId&#125; AND u.status=1;</span><br><span class="line">&lt;/select&gt;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
    <category term="RBAC权限模型" scheme="http://example.com/tags/RBAC%E6%9D%83%E9%99%90%E6%A8%A1%E5%9E%8B/"/>
    
  </entry>
  
  <entry>
    <title>uni-app</title>
    <link href="http://example.com/posts/e19785da.html"/>
    <id>http://example.com/posts/e19785da.html</id>
    <published>2024-08-04T08:08:23.000Z</published>
    <updated>2024-08-05T11:45:20.563Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="uni-app"><a href="#uni-app" class="headerlink" title="uni-app"></a>uni-app</h1><h2 id="一、uni-app工程目录结构"><a href="#一、uni-app工程目录结构" class="headerlink" title="一、uni-app工程目录结构"></a>一、uni-app工程目录结构</h2><p>uni-app项目创建出来之后，目录结构如下：</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240804160950.png"></p><table><thead><tr><th align="center">序号</th><th align="center">结构</th><th align="center">用途</th></tr></thead><tbody><tr><td align="center">1</td><td align="center">pages目录</td><td align="center">存放页面文件</td></tr><tr><td align="center">2</td><td align="center">static目录</td><td align="center">存放静态文件（图片）</td></tr><tr><td align="center">3</td><td align="center">App.vue文件</td><td align="center">所有小程序页面都被引用到该文件运行</td></tr><tr><td align="center">4</td><td align="center">main.js文件</td><td align="center">项目入口文件，用来初始化VUE对象，定义全局组件等</td></tr><tr><td align="center">5</td><td align="center">manifest.json文件</td><td align="center">工程配置文件，声明应用的名称、图标、权限等</td></tr><tr><td align="center">6</td><td align="center">pages.json文件</td><td align="center">页面注册文件，配置页面路径、窗口样式、标题文字等</td></tr><tr><td align="center">7</td><td align="center">uni.scss文件</td><td align="center">全局样式文件</td></tr></tbody></table><h2 id="二、练习"><a href="#二、练习" class="headerlink" title="二、练习"></a>二、练习</h2><h3 id="在pages目录中创建demo页面"><a href="#在pages目录中创建demo页面" class="headerlink" title="在pages目录中创建demo页面"></a>在pages目录中创建demo页面</h3><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240804163507.png"></p><h3 id="在pages-json文件中，把demo页面设置为第一个页面"><a href="#在pages-json文件中，把demo页面设置为第一个页面" class="headerlink" title="在pages.json文件中，把demo页面设置为第一个页面"></a>在pages.json文件中，把demo页面设置为第一个页面</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">&#123;</span><br><span class="line">&quot;pages&quot;: [ //pages数组中第一项表示应用启动页，参考：https://uniapp.dcloud.io/collocation/pages</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">    &quot;path&quot; : &quot;pages/demo/demo/demo&quot;,</span><br><span class="line">    &quot;style&quot; :                                                                                    </span><br><span class="line">    &#123;</span><br><span class="line">        &quot;navigationBarTitleText&quot;: &quot;&quot;,</span><br><span class="line">        &quot;enablePullDownRefresh&quot;: false</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;,</span><br><span class="line">&#123;</span><br><span class="line">&quot;path&quot;: &quot;pages/index/index&quot;,</span><br><span class="line">&quot;style&quot;: &#123;</span><br><span class="line">&quot;navigationBarTitleText&quot;: &quot;uni-app&quot;</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">&quot;globalStyle&quot;: &#123;</span><br><span class="line">&quot;navigationBarTextStyle&quot;: &quot;black&quot;,</span><br><span class="line">&quot;navigationBarTitleText&quot;: &quot;uni-app&quot;,</span><br><span class="line">&quot;navigationBarBackgroundColor&quot;: &quot;#F8F8F8&quot;,</span><br><span class="line">&quot;backgroundColor&quot;: &quot;#F8F8F8&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot;uniIdRouter&quot;: &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-编写demo-vue文件"><a href="#3-编写demo-vue文件" class="headerlink" title="3.编写demo.vue文件"></a>3.编写demo.vue文件</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">&lt;template&gt;</span><br><span class="line">&lt;view&gt;</span><br><span class="line">&lt;view&gt;fsdbniusdhfbi&lt;/view&gt;</span><br><span class="line">&lt;view&gt;&#123;&#123;username&#125;&#125;&lt;/view&gt;</span><br><span class="line">&lt;view v-for=&quot;one in tel&quot;&gt;&#123;&#123;one&#125;&#125;&lt;/view&gt;</span><br><span class="line">&lt;view v-if=&quot;age&gt;=18&quot;&gt;</span><br><span class="line">&lt;button @tap=&quot;signUP&quot;&gt;我要报名&lt;/button&gt;</span><br><span class="line">&lt;/view&gt;</span><br><span class="line"></span><br><span class="line">&lt;/view&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">export default &#123;</span><br><span class="line">data() &#123;</span><br><span class="line">return &#123;</span><br><span class="line">username: &quot;tom&quot;,</span><br><span class="line">tel: [&#x27;132131&#x27;,&#x27;464646&#x27;],</span><br><span class="line">age: 20</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">&#125;,</span><br><span class="line">methods: &#123;</span><br><span class="line">signUP:function()&#123;</span><br><span class="line">uni.showToast(&#123;</span><br><span class="line">title:&quot;点击了报名按钮&quot;</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">&lt;style&gt;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><p>@tap为点击事件</p></li><li><pre><code>面包屑函数signUP:function()&#123;                uni.showToast(&#123;                    title:&quot;点击了报名按钮&quot;                &#125;)            &#125;<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">  </span><br><span class="line"></span><br><span class="line">![](https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240804163742.png)</span><br><span class="line"></span><br><span class="line">- 双向绑定 b-moudel</span><br><span class="line"></span><br></pre></td></tr></table></figure>&lt;template&gt;    &lt;view&gt;        &lt;view&gt;fsdbniusdhfbi&lt;/view&gt;        &lt;view&gt;&#123;&#123;username&#125;&#125;&lt;/view&gt;        &lt;view v-for=&quot;one in tel&quot;&gt;&#123;&#123;one&#125;&#125;&lt;/view&gt;        &lt;view v-if=&quot;age&gt;=18&quot;&gt;            &lt;button @tap=&quot;signUP&quot;&gt;我要报名&lt;/button&gt;        &lt;/view&gt;        &lt;view&gt;            &lt;input type=&quot;text&quot; v-model=&quot;address&quot; placeholder=&quot;请输入&quot;/&gt;        &lt;/view&gt;                &lt;view&gt;&#123;&#123;address&#125;&#125;&lt;/view&gt;            &lt;/view&gt;&lt;/template&gt;&lt;script&gt;    export default &#123;        data() &#123;            return &#123;                username: &quot;tom&quot;,                tel: [&#39;132131&#39;,&#39;464646&#39;],                age: 20,                address: &quot;&quot;                            &#125;        &#125;,        methods: &#123;            signUP:function()&#123;                uni.showToast(&#123;                    title:&quot;点击了报名按钮&quot;                &#125;)            &#125;        &#125;    &#125;&lt;/script&gt;&lt;style&gt;&lt;/style&gt;</code></pre></li></ul><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240804170902.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
    <category term="前端开发" scheme="http://example.com/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
  </entry>
  
  <entry>
    <title>Shiro和JWT</title>
    <link href="http://example.com/posts/859172f9.html"/>
    <id>http://example.com/posts/859172f9.html</id>
    <published>2024-08-03T06:22:52.000Z</published>
    <updated>2024-08-05T11:44:31.611Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="Shiro和JWT技术"><a href="#Shiro和JWT技术" class="headerlink" title="Shiro和JWT技术"></a>Shiro和JWT技术</h1><h2 id="一、Shiro简介"><a href="#一、Shiro简介" class="headerlink" title="一、Shiro简介"></a>一、Shiro简介</h2><p>Shiro是Java领域非常知名的认证（Authentication）与授权（Authorization<br>）框架，用以替代JavaEE中的JAAS功能。相较于其他认证与授权框架，Shiro设计的非常简单，所以广受好评。任意JavaWeb项目都可以使用Shiro框架，而Spring Security必须要使用在Spring项目中。所以Shiro的适用性更加广泛。JFinal和Nutz非Spring框架都可以使用Shiro，而不能使用Spring Security框架。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803142439.png"></p><h3 id="什么是认证？"><a href="#什么是认证？" class="headerlink" title="什么是认证？"></a>什么是认证？</h3><p>​认证就是要核验用户的身份，比如说通过用户名和密码来检验用户的身份。说简单一些，认证就是登陆。登陆之后Shiro要记录用户成功登陆的凭证。</p><h3 id="什么是授权？"><a href="#什么是授权？" class="headerlink" title="什么是授权？"></a>什么是授权？</h3><p>​授权是比认证更加精细度的划分用户的行为。比如说一个教务管理系统中，学生登陆之后只能查看信息，不能修改信息。而班主任就可以修改学生的信息。这就是利用授权来限定不同身份用户的行为。</p><h3 id="Shiro靠什么做认证与授权的？"><a href="#Shiro靠什么做认证与授权的？" class="headerlink" title="Shiro靠什么做认证与授权的？"></a>Shiro靠什么做认证与授权的？</h3><p>​Shiro可以利用HttpSession或者Redis存储用户的登陆凭证，以及角色或者身份信息。然后利用过滤器（Filter），对每个Http请求过滤，检查请求对应HttpSession<br>或者Redis中的认证与授权信息。如果用户没有登陆，或者权限不够，那么Shiro会向客户端返回错误信息。也就是说，我们写用户登陆模块的时候，用户登陆成功之后，要调用Shiro保存登陆凭证。然后查询用户的角色和权限，让Shiro存储起来。将来不管哪个方法需要登陆访问，或者拥有特定的角色跟权限才能访问，我们在方法前设置注解即可，非常简单。</p><h2 id="二、JWT简介"><a href="#二、JWT简介" class="headerlink" title="二、JWT简介"></a>二、JWT简介</h2><p>​JWT（Json Web Token）, 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。JWT一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息，以便于从资源服务器获取资源，也可以增加一些额外的其它业务逻辑所必须的声明信息，该token也可直接被用于认证，也可被加密。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803143121.png"></p><h3 id="JWT可以用在单点登录的系统中"><a href="#JWT可以用在单点登录的系统中" class="headerlink" title="JWT可以用在单点登录的系统中"></a>JWT可以用在单点登录的系统中</h3><p>传统的JavaWeb项目，利用HttpSession保存用户的登陆凭证。如果后端系统采用了负载均衡设计，当用户在A节点成功登陆，那么登陆凭证保存在A节点的HttpSession中。如果用户下一个请求被负载均衡到了B节点，因为B节点上面没有用户的登陆凭证，所以需要用户重新登录，这个体验太糟糕了。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803143328.png"></p><p>​如果用户的登陆凭证经过加密（Token）保存在客户端，客户端每次提交请求的时候，把Token上传给后端服务器节点。即便后端项目使用了负载均衡，每个后端节点接收到客户端上传的Token之后，经过检测，是有效的Token，于是就断定用户已经成功登陆，接下来就可以提供后端服务了。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803143646.png"></p><h3 id="JWT兼容更多的客户端"><a href="#JWT兼容更多的客户端" class="headerlink" title="JWT兼容更多的客户端"></a>JWT兼容更多的客户端</h3><p>​传统的HttpSession依靠浏览器的Cookie存放SessionId，所以要求客户端必须是浏览器。现在的JavaWeb系统，客户端可以是浏览器、APP、小程序，以及物联网设备。为了让这些设备都能访问到JavaWeb项目，就必须要引入JWT技术。JWT的Token是纯字符串，至于客户端怎么保存，没有具体要求。只要客户端发起请求的时候，附带上Token即可。所以像物联网设备，我们可以用SQLite存储Token数据。</p><h2 id="三、创建JWT工具类"><a href="#三、创建JWT工具类" class="headerlink" title="三、创建JWT工具类"></a>三、创建JWT工具类</h2><p>JWT的Token要经过加密才能返回给客户端，包括客户端上传的Token，后端项目需要验证核实。于是我们需要一个JWT工具类，用来加密Token和验证Token的有效性。</p><h3 id="3-1导入依赖库"><a href="#3-1导入依赖库" class="headerlink" title="3.1导入依赖库"></a>3.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><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">&lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;shiro-web&lt;/artifactId&gt;</span><br><span class="line">          &lt;version&gt;1.5.3&lt;/version&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br><span class="line">      &lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;shiro-spring&lt;/artifactId&gt;</span><br><span class="line">          &lt;version&gt;1.5.3&lt;/version&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br><span class="line">      &lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;com.auth0&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;java-jwt&lt;/artifactId&gt;</span><br><span class="line">          &lt;version&gt;3.10.3&lt;/version&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br><span class="line">      &lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;spring-boot-configuration-processor&lt;/artifactId&gt;</span><br><span class="line">          &lt;optional&gt;true&lt;/optional&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br><span class="line">      &lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;commons-lang3&lt;/artifactId&gt;</span><br><span class="line">          &lt;version&gt;3.11&lt;/version&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br><span class="line">      &lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;httpcore&lt;/artifactId&gt;</span><br><span class="line">          &lt;version&gt;4.4.13&lt;/version&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br><span class="line">      &lt;dependency&gt;</span><br><span class="line">          &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">          &lt;artifactId&gt;spring-boot-starter-aop&lt;/artifactId&gt;</span><br><span class="line">      &lt;/dependency&gt;</span><br></pre></td></tr></table></figure><h3 id="3-2、定义密钥和过期时间"><a href="#3-2、定义密钥和过期时间" class="headerlink" title="3.2、定义密钥和过期时间"></a>3.2、定义密钥和过期时间</h3><p>放在yml文件里，进行值注入</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">aaa:</span><br><span class="line">  jwt:</span><br><span class="line">    secret: abc123456</span><br><span class="line">    #令牌过期时间（天）</span><br><span class="line">    expire: 5</span><br><span class="line">    #缓存时间（天）</span><br><span class="line">    cache-expire: 10</span><br></pre></td></tr></table></figure><h3 id="3-3、工具类"><a href="#3-3、工具类" class="headerlink" title="3.3、工具类"></a>3.3、工具类</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"></span><br><span class="line">@Component</span><br><span class="line">@Slf4j</span><br><span class="line">public class JwtUtil &#123;</span><br><span class="line">    @Value(&quot;$&#123;aaa.jwt.secret&#125;&quot;)</span><br><span class="line">    private String secret;</span><br><span class="line">    @Value(&quot;$&#123;aaa.jwt.expire&#125;&quot;)</span><br><span class="line">    private int expire;</span><br><span class="line"></span><br><span class="line">    public String createToken(int userId) &#123;</span><br><span class="line">        //        DateField.DAY_OF_YEAR单位为天，5天后过期</span><br><span class="line">        Date date = DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, 5);</span><br><span class="line">//        HMAC256加密,</span><br><span class="line">        Algorithm algorithm = Algorithm.HMAC256(secret);</span><br><span class="line">        JWTCreator.Builder builder = JWT.create();</span><br><span class="line">        String token = builder.withClaim(&quot;userId&quot;, userId).withExpiresAt(date).sign(algorithm);</span><br><span class="line"></span><br><span class="line">        return token;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   public int getUserId(String token) &#123;</span><br><span class="line">       DecodedJWT jwt = JWT.decode(token);</span><br><span class="line">       int userId = jwt.getClaim(&quot;userId&quot;).asInt();</span><br><span class="line">       return userId;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">//    校验</span><br><span class="line">   public void verify(String token) &#123;</span><br><span class="line">       Algorithm algorithm=Algorithm.HMAC256(secret);</span><br><span class="line">       JWTVerifier verifier=JWT.require(algorithm).build();</span><br><span class="line">       verifier.verify(token);</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><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="四、令牌封装为认证对象"><a href="#四、令牌封装为认证对象" class="headerlink" title="四、令牌封装为认证对象"></a>四、令牌封装为认证对象</h2><p>我们要把JWT和Shiro框架对接起来，这样Shiro框架就会拦截所有的Http请求，然后验证请求提交的<br>Token是否有效。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803151644.png"></p><p>客户端提交的Token不能直接交给Shiro框架，需要先封装成AuthenticationToken 类型的对象，所以我们我们需要先创建AuthenticationToken的实现类。</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">过滤器拦截HTTP请求，把拦截下来的token字符串封装到token对象中，把token对象传给Realm类去做认证。</span><br></pre></td></tr></table></figure><h3 id="封装token"><a href="#封装token" class="headerlink" title="封装token"></a>封装token</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></pre></td><td class="code"><pre><span class="line">package com.example.emos.wx.config.shiro;</span><br><span class="line"></span><br><span class="line">import org.apache.shiro.authc.AuthenticationToken;</span><br><span class="line"></span><br><span class="line">public class OAuth2Token implements AuthenticationToken &#123;</span><br><span class="line">    </span><br><span class="line">    private String token;</span><br><span class="line"></span><br><span class="line">    public OAuth2Token(String token) &#123;</span><br><span class="line">        this.token = token;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public Object getPrincipal() &#123;</span><br><span class="line">        return token;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public Object getCredentials() &#123;</span><br><span class="line">        return token;</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="创建OAuth2Realm类"><a href="#创建OAuth2Realm类" class="headerlink" title="创建OAuth2Realm类"></a>创建OAuth2Realm类</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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line">import org.apache.shiro.authc.AuthenticationException;</span><br><span class="line">import org.apache.shiro.authc.AuthenticationInfo;</span><br><span class="line">import org.apache.shiro.authc.AuthenticationToken;</span><br><span class="line">import org.apache.shiro.authc.SimpleAuthenticationInfo;</span><br><span class="line">import org.apache.shiro.authz.AuthorizationInfo;</span><br><span class="line">import org.apache.shiro.authz.SimpleAuthorizationInfo;</span><br><span class="line">import org.apache.shiro.realm.AuthorizingRealm;</span><br><span class="line">import org.apache.shiro.subject.PrincipalCollection;</span><br><span class="line">import org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line">import org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line">@Component</span><br><span class="line">public class OAuth2Realm extends AuthorizingRealm&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    @Autowired</span><br><span class="line">    private JwtUtil jwtUtil;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 判断是否支持此token(令牌的类型)</span><br><span class="line">     * @param token</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public boolean supports(AuthenticationToken token) &#123;</span><br><span class="line">        return token instanceof OAuth2Token;</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 principalCollection</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) &#123;</span><br><span class="line">        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();</span><br><span class="line">        // TODO  查询用户权限列表</span><br><span class="line">        // TODO  往info里添加权限列表</span><br><span class="line"></span><br><span class="line">        return info;</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 authenticationToken</span><br><span class="line">     * @return</span><br><span class="line">     * @throws AuthenticationException</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException &#123;</span><br><span class="line"></span><br><span class="line">        //TODO 从令牌获取userid，检验用户是否被冻结</span><br><span class="line">        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo();</span><br><span class="line"></span><br><span class="line">        // TODO 往info里添加信息，token字符串，返回给shiro</span><br><span class="line"></span><br><span class="line">        return info;</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="刷新令牌如何设计"><a href="#刷新令牌如何设计" class="headerlink" title="刷新令牌如何设计"></a>刷新令牌如何设计</h3><h4 id="一、为什么要刷新Token的过期时间？"><a href="#一、为什么要刷新Token的过期时间？" class="headerlink" title="一、为什么要刷新Token的过期时间？"></a>一、为什么要刷新Token的过期时间？</h4><p>我们在定义JwtUtil工具类的时候，生成的Token都有过期时间。那么问题来了，假设Token过期时间为15天，用户在第14天的时候，还可以免登录正常访问系统。但是到了第15天，用户的Token过期，于是用户需要重新登录系统。<br>HttpSession的过期时间比较优雅，默认为15分钟。如果用户连续使用系统，只要间隔时间不超过15分钟，系统就不会销毁HttpSession对象。JWT的令牌过期时间能不能做成HttpSession那样超时时间，只要用户间隔操作时间不超过15天，系统就不需要用户重新登录系统。实现这种效果的方案有两种：</p><ul><li><p>双Token</p></li><li><p>Token缓存</p></li><li><p>双令牌机制</p><ul><li>设置长短日期的令牌</li><li>短日期令牌失效就用长日期</li></ul></li><li><p>缓存令牌机制</p><ul><li>令牌缓存到redis上</li><li>缓存的过期时间是客户端令牌的一倍</li><li>如果客户端令牌过期，缓存的令牌没有过期，则生成新的令牌</li><li>全都过期就重新登陆</li></ul></li></ul><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803175109.png"></p><p>Token缓存方案是把Token缓存到Redis，然后设置Redis里面缓存的Token过期时间为正常Token的1倍,然后根据情况刷新Token的过期时间。</p><p><strong>Token失效，缓存也不存在的情况：</strong><br>当第15天，用户的Token失效以后，我们让Shiro程序到Redis查看是否存在缓存的Token，如果这个Token不存在于Redis里面，就说明用户的操作间隔了15天，需要重新登录。</p><p><strong>Token失效，但是缓存还存在的情况：</strong><br>如果Redis中存在缓存的Token，说明当前Token失效后，间隔时间还没有超过15天，不应该让用户重新登录。所以要生成新的Token返回给客户端，并且把这个Token缓存到Redis里面，这种操作成为刷新Token过期时间。</p><h4 id="二、客户端如何更新令牌？"><a href="#二、客户端如何更新令牌？" class="headerlink" title="二、客户端如何更新令牌？"></a>二、客户端如何更新令牌？</h4><p>​在我们的方案中，服务端刷新Token过期时间，其实就是生成一个新的Token给客户端。那么客户端怎么知道这次响应带回来的Token是更新过的呢？这个问题很容易解决。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803175555.png"></p><p>​只要用户成功登陆系统，当后端服务器更新Token的时候，就在响应中添加Token。客户端那边判断每次Ajax响应里面是否包含Token，如果包含，就把Token保存起来就可以了。</p><h4 id="三、如何在响应中添加令牌？"><a href="#三、如何在响应中添加令牌？" class="headerlink" title="三、如何在响应中添加令牌？"></a>三、如何在响应中添加令牌？</h4><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803180246.png"></p><p>​我们定义OAuth2Filter类拦截所有的HTTP请求，一方面它会把请求中的Token字符串提取出来，封装成对象交给Shiro框架；另一方面，它会检查Token的有效性。如果Token过期，那么会生成新的Token，分别存储在ThreadLocalToken和Redis中。之所以要把新令牌保存到ThreadLocalToken里面，是因为要向AOP切面类传递这个新令牌。虽然OAuth2Filter中有doFilterInternal()方法，我们可以得到响应并且写入新令牌。但是这个做非常麻烦，首先我们要通过IO流读取响应中的数据，然后还要把数据解析成JSON对象，最后再放入这个新令牌。如果我们定义了AOP切面类，拦截所有Web方法返回的R对象，然后在R对象里面添加新令牌，这多简单啊。但是OAuth2Filter和AOP切面类之间没有调用关系，所以我们难把新令牌传给AOP切面类。这里我想到了ThreadLocal，只要是同一个线程，往ThreadLocal里面写入数据和读取数据是完全相同的。在Web项目中，从OAuth2Filter到AOP切面类，都是由同一个线程来执行的，中途不会更换线程。所以我们可以放心的把新令牌保存都在ThreadLocal里面，AOP切面类可以成功的取出新令牌，然后往R对象里面添加新令牌即可。ThreadLocalToken是自定义的类，里面包含了ThreadLocal类型的变量，可以用来保存线程安全的数据，而且避免了使用线程锁。</p><h4 id="四、创建ThreadLocalToken类"><a href="#四、创建ThreadLocalToken类" class="headerlink" title="四、创建ThreadLocalToken类"></a>四、创建ThreadLocalToken类</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">package com.example.emos.wx.config.shiro;</span><br><span class="line"></span><br><span class="line">import org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line">@Component</span><br><span class="line">public class ThreadLocalToken &#123;</span><br><span class="line"></span><br><span class="line">    private ThreadLocal&lt;String&gt; local=new ThreadLocal&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    public String getToken()</span><br><span class="line">    &#123;</span><br><span class="line">        return  (String) local.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setToken(String token)</span><br><span class="line">    &#123;</span><br><span class="line">        local.set(token);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    public void clear()</span><br><span class="line">    &#123;</span><br><span class="line">        local.remove();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="伍、创建过滤器"><a href="#伍、创建过滤器" class="headerlink" title="伍、创建过滤器"></a>伍、创建过滤器</h4><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803182411.png"></p><p>​</p><p><strong>注意事项：</strong>因为在OAuth2Filter类中要读写ThreadLocal中的数据，所以OAuth2Filter类必须要设置成多例的，否则ThreadLocal将无法使用。</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></pre></td><td class="code"><pre><span class="line">package com.example.emos.wx.config.shiro;</span><br><span class="line"></span><br><span class="line">import cn.hutool.core.util.StrUtil;</span><br><span class="line">import com.auth0.jwt.exceptions.JWTDecodeException;</span><br><span class="line">import com.auth0.jwt.exceptions.TokenExpiredException;</span><br><span class="line">import org.apache.http.HttpStatus;</span><br><span class="line">import org.apache.shiro.authc.AuthenticationException;</span><br><span class="line">import org.apache.shiro.authc.AuthenticationToken;</span><br><span class="line">import org.apache.shiro.web.filter.authc.AuthenticatingFilter;</span><br><span class="line">import org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line">import org.springframework.beans.factory.annotation.Value;</span><br><span class="line">import org.springframework.context.annotation.Scope;</span><br><span class="line">import org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line">import org.springframework.stereotype.Component;</span><br><span class="line">import org.springframework.web.bind.annotation.RequestMethod;</span><br><span class="line"></span><br><span class="line">import javax.servlet.FilterChain;</span><br><span class="line">import javax.servlet.ServletException;</span><br><span class="line">import javax.servlet.ServletRequest;</span><br><span class="line">import javax.servlet.ServletResponse;</span><br><span class="line">import javax.servlet.http.HttpServletRequest;</span><br><span class="line">import javax.servlet.http.HttpServletResponse;</span><br><span class="line">import java.io.IOException;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line">@Component</span><br><span class="line">@Scope(&quot;prototype&quot;)</span><br><span class="line">//设置多例否则向ThreadLocalToken存储会出问题</span><br><span class="line">public class OAuth2Filter extends AuthenticatingFilter &#123;</span><br><span class="line">    @Autowired</span><br><span class="line">    private ThreadLocalToken threadLocalToken;</span><br><span class="line"></span><br><span class="line">    @Value(&quot;$&#123;emos.jwt.cache-expire&#125;&quot;)</span><br><span class="line">    private int cacheExpire;</span><br><span class="line"></span><br><span class="line">    @Autowired</span><br><span class="line">    private JwtUtil jwtUtil;</span><br><span class="line"></span><br><span class="line">    @Autowired</span><br><span class="line">    private RedisTemplate redisTemplate;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 拦截下后封装令牌字符串为令牌对象</span><br><span class="line">     * @param request</span><br><span class="line">     * @param response</span><br><span class="line">     * @return</span><br><span class="line">     * @throws Exception</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception &#123;</span><br><span class="line">        HttpServletRequest req= (HttpServletRequest) request;</span><br><span class="line">        String token=getRequestToken(req);</span><br><span class="line">        if(StrUtil.isBlank(token))&#123;</span><br><span class="line">            return null;</span><br><span class="line">        &#125;</span><br><span class="line">        return new OAuth2Token(token);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 拦截请求，判断请求是否需要被Shiro处理</span><br><span class="line">     * @param request</span><br><span class="line">     * @param response</span><br><span class="line">     * @param mappedValue</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) &#123;</span><br><span class="line">        HttpServletRequest req= (HttpServletRequest) request;</span><br><span class="line">// Ajax提交application/json数据的时候，会先发出Options请求</span><br><span class="line"></span><br><span class="line">// 这里要放行Options请求，不需要Shiro处理</span><br><span class="line">        if(req.getMethod().equals(RequestMethod.OPTIONS.name()))&#123;</span><br><span class="line">            return true;</span><br><span class="line">        &#125;</span><br><span class="line">        // 除了Options请求之外，所有请求都要被Shiro处理</span><br><span class="line">        return false;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 该方法用于处理所有应该被Shiro处理的请求</span><br><span class="line">     * @param request</span><br><span class="line">     * @param response</span><br><span class="line">     * @return</span><br><span class="line">     * @throws Exception</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception &#123;</span><br><span class="line">        HttpServletRequest req= (HttpServletRequest) request;</span><br><span class="line">        HttpServletResponse resp= (HttpServletResponse) response;</span><br><span class="line">        resp.setContentType(&quot;text/html&quot;);</span><br><span class="line">        resp.setCharacterEncoding(&quot;UTF-8&quot;);</span><br><span class="line">//      允许跨域请求</span><br><span class="line">        resp.setHeader(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);</span><br><span class="line">        resp.setHeader(&quot;Access-Control-Allow-Origin&quot;, req.getHeader(&quot;Origin&quot;));</span><br><span class="line"></span><br><span class="line">        threadLocalToken.clear();</span><br><span class="line"></span><br><span class="line">        String token=getRequestToken(req);</span><br><span class="line">        if(StrUtil.isBlank(token))&#123;</span><br><span class="line">            resp.setStatus(HttpStatus.SC_UNAUTHORIZED);</span><br><span class="line">            resp.getWriter().print(&quot;无效的令牌&quot;);</span><br><span class="line">            return false;</span><br><span class="line">        &#125;</span><br><span class="line">//        检查令牌是否过期</span><br><span class="line">        try&#123;</span><br><span class="line">            jwtUtil.verifierToken(token);</span><br><span class="line">        &#125;catch (TokenExpiredException e)&#123;</span><br><span class="line">//        客户端令牌过期，查询Redis中是否存在令牌，如果存在令牌就重新生成一个令牌给客户端</span><br><span class="line">            if(redisTemplate.hasKey(token))&#123;</span><br><span class="line">                redisTemplate.delete(token);</span><br><span class="line">                int userId=jwtUtil.getUserId(token);</span><br><span class="line">                token=jwtUtil.createToken(userId);</span><br><span class="line">                redisTemplate.opsForValue().set(token,userId+&quot;&quot;,cacheExpire, TimeUnit.DAYS);</span><br><span class="line">//                把新令牌绑定到线程</span><br><span class="line">                threadLocalToken.setToken(token);</span><br><span class="line">            &#125;</span><br><span class="line">            else&#123;</span><br><span class="line">                resp.setStatus(HttpStatus.SC_UNAUTHORIZED);</span><br><span class="line">                resp.getWriter().print(&quot;令牌已过期&quot;);</span><br><span class="line">                return false;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;catch (Exception e)&#123;</span><br><span class="line">            resp.setStatus(HttpStatus.SC_UNAUTHORIZED);</span><br><span class="line">            resp.getWriter().print(&quot;无效的令牌&quot;);</span><br><span class="line">            return false;</span><br><span class="line">        &#125;</span><br><span class="line">//        间接调用realm类</span><br><span class="line">        boolean bool=executeLogin(request,response);</span><br><span class="line">        return bool;</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 token</span><br><span class="line">     * @param e</span><br><span class="line">     * @param request</span><br><span class="line">     * @param response</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) &#123;</span><br><span class="line">        HttpServletRequest req= (HttpServletRequest) request;</span><br><span class="line">        HttpServletResponse resp= (HttpServletResponse) response;</span><br><span class="line">        resp.setContentType(&quot;text/html&quot;);</span><br><span class="line">        resp.setCharacterEncoding(&quot;UTF-8&quot;);</span><br><span class="line">        resp.setHeader(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);</span><br><span class="line">        resp.setHeader(&quot;Access-Control-Allow-Origin&quot;, req.getHeader(&quot;Origin&quot;));</span><br><span class="line">        resp.setStatus(HttpStatus.SC_UNAUTHORIZED);</span><br><span class="line">        try&#123;</span><br><span class="line">            resp.getWriter().print(e.getMessage());</span><br><span class="line">        &#125;catch (Exception exception)&#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        return false;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException &#123;</span><br><span class="line">        HttpServletRequest req= (HttpServletRequest) request;</span><br><span class="line">        HttpServletResponse resp= (HttpServletResponse) response;</span><br><span class="line">        resp.setContentType(&quot;text/html&quot;);</span><br><span class="line">        resp.setCharacterEncoding(&quot;UTF-8&quot;);</span><br><span class="line">        resp.setHeader(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);</span><br><span class="line">        resp.setHeader(&quot;Access-Control-Allow-Origin&quot;, req.getHeader(&quot;Origin&quot;));</span><br><span class="line">        super.doFilterInternal(request, response, chain);</span><br><span class="line"></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 request</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    private String getRequestToken(HttpServletRequest request)&#123;</span><br><span class="line">        String token=request.getHeader(&quot;token&quot;);</span><br><span class="line">        if(StrUtil.isBlank(token))&#123;</span><br><span class="line">            token=request.getParameter(&quot;token&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        return token;</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="六、创建ShiroConfig类"><a href="#六、创建ShiroConfig类" class="headerlink" title="六、创建ShiroConfig类"></a>六、创建ShiroConfig类</h4><p>我们要创建的ShiroConfig类，是用来把OAuth2Filter和OAuth2Realm配置到Shiro框架，这样我们辛苦搭建的Shiro+JWT才算生效。</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803190823.png"></p><p><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></pre></td><td class="code"><pre><span class="line">package com.example.emos.wx.config.shiro;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">import org.apache.shiro.mgt.SecurityManager;</span><br><span class="line">import org.apache.shiro.spring.LifecycleBeanPostProcessor;</span><br><span class="line">import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;</span><br><span class="line">import org.apache.shiro.spring.web.ShiroFilterFactoryBean;</span><br><span class="line">import org.apache.shiro.web.mgt.DefaultWebSecurityManager;</span><br><span class="line">import org.springframework.context.annotation.Bean;</span><br><span class="line">import org.springframework.context.annotation.Configuration;</span><br><span class="line"></span><br><span class="line">import javax.servlet.Filter;</span><br><span class="line">import java.util.HashMap;</span><br><span class="line">import java.util.LinkedHashMap;</span><br><span class="line">import java.util.Map;</span><br><span class="line"></span><br><span class="line">@Configuration</span><br><span class="line">public class ShiroConfig &#123;</span><br><span class="line"></span><br><span class="line">    @Bean(&quot;securityManager&quot;)</span><br><span class="line">    public SecurityManager securityManager(OAuth2Realm realm)&#123;</span><br><span class="line">        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();</span><br><span class="line">        securityManager.setRealm(realm);</span><br><span class="line">        securityManager.setRememberMeManager(null);</span><br><span class="line">        return securityManager;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Bean(&quot;shiroFilter&quot;)</span><br><span class="line">    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager,OAuth2Filter filter)&#123;</span><br><span class="line">        ShiroFilterFactoryBean shiroFilter=new ShiroFilterFactoryBean();</span><br><span class="line">        shiroFilter.setSecurityManager(securityManager);</span><br><span class="line"></span><br><span class="line">        Map&lt;String , Filter&gt; map=new HashMap&lt;&gt;();</span><br><span class="line">        map.put(&quot;oauth2&quot;,filter);</span><br><span class="line">        shiroFilter.setFilters(map);</span><br><span class="line"></span><br><span class="line">        Map&lt;String,String&gt; filterMap=new LinkedHashMap&lt;&gt;();</span><br><span class="line">        filterMap.put(&quot;/webjars/**&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/druid/**&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/app/**&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/sys/login&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/swagger/**&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/v2/api-docs&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/swagger-ui.html&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/swagger-resources/**&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/captcha.jpg&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/user/register&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/user/login&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/test/**&quot;, &quot;anon&quot;);</span><br><span class="line">        filterMap.put(&quot;/meeting/recieveNotify&quot;, &quot;anon&quot;);</span><br><span class="line">//        除了上面的请求都需要认证</span><br><span class="line">        filterMap.put(&quot;/**&quot;, &quot;oauth2&quot;);</span><br><span class="line"></span><br><span class="line">        shiroFilter.setFilterChainDefinitionMap(filterMap);</span><br><span class="line"></span><br><span class="line">        return shiroFilter;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Bean(&quot;lifecycleBeanPostProcessor&quot;)</span><br><span class="line">    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor()&#123;</span><br><span class="line">        return new LifecycleBeanPostProcessor();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Bean</span><br><span class="line">    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager)&#123;</span><br><span class="line">        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();</span><br><span class="line">        advisor.setSecurityManager(securityManager);</span><br><span class="line">        return advisor;</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="七、创建AOP切面类"><a href="#七、创建AOP切面类" class="headerlink" title="七、创建AOP切面类"></a>七、创建AOP切面类</h4><p>我们要在请求与响应中加入令牌</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803192304.png"></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></pre></td><td class="code"><pre><span class="line">package com.example.emos.wx.aop;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">import com.example.emos.wx.common.util.R;</span><br><span class="line">import com.example.emos.wx.config.shiro.ThreadLocalToken;</span><br><span class="line">import org.aspectj.lang.ProceedingJoinPoint;</span><br><span class="line">import org.aspectj.lang.annotation.Around;</span><br><span class="line">import org.aspectj.lang.annotation.Aspect;</span><br><span class="line">import org.aspectj.lang.annotation.Pointcut;</span><br><span class="line">import org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line">import org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line">@Aspect</span><br><span class="line">@Component</span><br><span class="line">public class TokenAspect &#123;</span><br><span class="line"></span><br><span class="line">    @Autowired</span><br><span class="line">    private ThreadLocalToken threadLocalToken;</span><br><span class="line"></span><br><span class="line">    @Pointcut(&quot;execution(public * com.example.emos.wx.controller.*.*(..)))&quot;)</span><br><span class="line">    public void aspect() &#123;</span><br><span class="line"></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">    @Around(&quot;aspect()&quot;)</span><br><span class="line">    public Object around(ProceedingJoinPoint joinPoint) throws Throwable &#123;</span><br><span class="line"></span><br><span class="line">        R r = (R)joinPoint.proceed();</span><br><span class="line"></span><br><span class="line">        String token = threadLocalToken.getToken();</span><br><span class="line"></span><br><span class="line">        if (token != null) &#123;</span><br><span class="line">            r.put(&quot;token&quot;, token);</span><br><span class="line">            threadLocalToken.clear();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        return r;</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">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="八、返回给客户端的异常"><a href="#八、返回给客户端的异常" class="headerlink" title="八、返回给客户端的异常"></a>八、返回给客户端的异常</h4><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240803204312.png"></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></pre></td><td class="code"><pre><span class="line">package com.example.emos.wx.config;</span><br><span class="line"></span><br><span class="line">import com.example.emos.wx.exception.EmosException;</span><br><span class="line">import lombok.extern.slf4j.Slf4j;</span><br><span class="line">import org.apache.shiro.authz.UnauthorizedException;</span><br><span class="line">import org.springframework.http.HttpStatus;</span><br><span class="line"></span><br><span class="line">import org.springframework.web.bind.MethodArgumentNotValidException;</span><br><span class="line">import org.springframework.web.bind.annotation.*;</span><br><span class="line"></span><br><span class="line">@RestControllerAdvice</span><br><span class="line">@Slf4j</span><br><span class="line">public class ExceptionAdvice &#123;</span><br><span class="line">    @ResponseBody</span><br><span class="line">    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)</span><br><span class="line">    @ExceptionHandler(Exception.class)</span><br><span class="line">//    捕获全局异常</span><br><span class="line">    public String validExceptionHandler(Exception e)&#123;</span><br><span class="line"></span><br><span class="line">        log.info(&quot;执行异常&quot;);</span><br><span class="line"></span><br><span class="line">        if(e instanceof MethodArgumentNotValidException)&#123;</span><br><span class="line">            MethodArgumentNotValidException exception= (MethodArgumentNotValidException) e;</span><br><span class="line">            return exception.getBindingResult().getFieldError().getDefaultMessage();</span><br><span class="line">        &#125;</span><br><span class="line">        else if(e instanceof EmosException)&#123;</span><br><span class="line">            EmosException exception= (EmosException) e;</span><br><span class="line">            return exception.getMsg();</span><br><span class="line">        &#125;</span><br><span class="line">        else if(e instanceof UnauthorizedException)&#123;</span><br><span class="line">            return &quot;你不具备相关权限&quot;;</span><br><span class="line">        &#125;</span><br><span class="line">        else&#123;</span><br><span class="line">            return &quot;后端执行异常&quot;;</span><br><span class="line">        &#125;</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><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="执行顺序"><a href="#执行顺序" class="headerlink" title="执行顺序"></a>执行顺序</h4><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240805194157.png"></p><h5 id="一、为什么XSSFilter最先执行？"><a href="#一、为什么XSSFilter最先执行？" class="headerlink" title="一、为什么XSSFilter最先执行？"></a>一、为什么XSSFilter最先执行？</h5><p>​Emos系统接收到HTTP请求之后，首先由XSSFilter来处理请求。因为XSSFilter是标准的Servlet过滤器，所以他执行的优先级要高于ShiroFilter和AOP拦截器的。这也很好理解，还没轮到Controller中的Web方法执行，AOP连接器自然不能运行。另外，XSSFilter使用@WebFilter注解定义出来的过滤器，所以他的优先级比SpringMVC中注册的Filter优先级更高，所以XSSFilter早于SpringMVC执行。这个也能说得通，我们希望先把请求中的数据先转义，然后再由SpringMVC框架来处理请求。</p><h5 id="二、OAuth2Filter的执行"><a href="#二、OAuth2Filter的执行" class="headerlink" title="二、OAuth2Filter的执行"></a>二、OAuth2Filter的执行</h5><p>​因为OAuth2Filter是在SpringMVC中注册的Filter，所以它晚于Servlet过滤器的执行。但是SpringMVC中注册过滤器有个好处，就是可以规定Filter的优先级别，所以定义普通的Filter，注册在SpringMVC上更加的妥当。</p><p>​我们在定义OAuth2Filter的时候，声明了很多的方法，但是在注册流程中，我们只能看到doFilterInternal()方法的执行，这又是为什么呢？</p><p>​我们声明Shiro过滤器拦截路径的时候，为登陆和注册路径下的请求，设置了放行，所以验证与授权并没有生效。等我们将来写具体的业务类型的Web方法，添加相关的Shiro注解，这时候OAuth2Filter中的其他方法就得以运行了。</p><h5 id="三、TokenAspect的作用"><a href="#三、TokenAspect的作用" class="headerlink" title="三、TokenAspect的作用"></a>三、TokenAspect的作用</h5><p>​TokenAspect是切面类，拦截所有Web方法的返回值。TokenAspect先检测ThreadLocalToken中有没有令牌字符串？如果有就把刷新后的令牌写入Web方法返回的R对象里面。因此说，Web方法每次执行的时候，TokenAspect都会随之运行，这在正常不过了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
    <category term="权限认证" scheme="http://example.com/tags/%E6%9D%83%E9%99%90%E8%AE%A4%E8%AF%81/"/>
    
  </entry>
  
  <entry>
    <title>抵御XSS攻击</title>
    <link href="http://example.com/posts/20174efb.html"/>
    <id>http://example.com/posts/20174efb.html</id>
    <published>2024-08-02T15:00:36.000Z</published>
    <updated>2024-08-02T15:51:28.935Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="抵御XSS攻击"><a href="#抵御XSS攻击" class="headerlink" title="抵御XSS攻击"></a>抵御XSS攻击</h1><p>​</p><p>XSS攻击通常指的是通过利用网页开发时留下的漏洞，通过巧妙的方法注入恶意指令代码到网页，使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript，但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后，攻击者可能得到包括但不限于更高的权限（如执行一些操作）、私密网页内容、会话和cookie等各种内容。<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">&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>，这段代码如果不经过转义处理，而直接保存到数据库。将来视图层渲染HTML的时候，把这段代码输出到页面上，那么<br>标签的内容就会被执行。<br>通常情况下，我们登陆到某个网站。如果网站使用HttpSession保存登陆凭证，那么SessionId会以Cookie的形式保存在浏览器上。如果黑客在这个网页发帖的时候，填写的JavaScript代码是用来获取Cookie内容的，并且把Cookie内容通过Ajax发送给黑客自己的电脑。于是只要有人在这个网站上浏览黑客发的帖子，那么视图层渲染HTML页面，就会执行注入的XSS脚本，于是你的Cookie信息就泄露了。黑客在自己的电脑上构建出Cookie，就可以冒充已经登陆的用户。即便很多网站使用了JWT，登陆凭证（Token令牌）是存储在浏览器上面的。所以用XSS脚本可以轻松的从Storage中提取出Token，黑客依然可以轻松的冒充已经登陆的用户。<br>所以避免XSS攻击最有效的办法就是对用户输入的数据进行转义，然后存储到数据库里面。等到视图层渲染HTML页面的时候。转义后的文字是不会被当做JavaScript执行的，这就可以抵御XSS攻击。</p><p>对HTTP请求中的数据进行转义 方法：</p><ul><li>设置过滤器</li><li>覆盖HTTP请求<ul><li>HTTPServletRequest是接口，各厂商会实现<ul><li>如果直接继承各厂商的请求父类子类覆盖方法，那么就会程序和厂商绑定在一起</li></ul></li><li>HTTPServletRequestWrapper类（包装类来增强请求功能）<ul><li>使用了装饰器模式</li><li>装饰器封装了厂商的request实现类</li><li>只需要覆盖Wrapper类的方法就能做到给请求对象增加新功能</li><li>创建一个过滤器，把请求对象传入wrapper中</li></ul></li></ul></li></ul><h2 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</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></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;cn.hutool&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;hutool-all&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;5.4.0&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure><h2 id="config包下加入配置类进行转义"><a href="#config包下加入配置类进行转义" class="headerlink" title="config包下加入配置类进行转义"></a>config包下加入配置类进行转义</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><span class="line">18</span><br><span class="line">19</span><br><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><br><span class="line">public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper &#123;</span><br><span class="line">    public XssHttpServletRequestWrapper(HttpServletRequest request) &#123;</span><br><span class="line">        super(request);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public String getParameter(String name) &#123;</span><br><span class="line">        String value = super.getParameter(name);</span><br><span class="line">        if (!StrUtil.hasEmpty(value))&#123;</span><br><span class="line">            value=HtmlUtil.filter(value);</span><br><span class="line">        &#125;</span><br><span class="line">        return value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public String[] getParameterValues(String name) &#123;</span><br><span class="line">        String[] values = super.getParameterValues(name);</span><br><span class="line">        if (values != null) &#123;</span><br><span class="line">            for (int i = 0; i &lt; values.length; i++) &#123;</span><br><span class="line">                String value = values[i];</span><br><span class="line">                if (!StrUtil.hasEmpty(value))&#123;</span><br><span class="line">                    value=HtmlUtil.filter(value);</span><br><span class="line">                &#125;</span><br><span class="line">                values[i]=value;</span><br><span class="line">            &#125;</span><br><span class="line">         &#125;</span><br><span class="line">        return values;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public Map&lt;String, String[]&gt; getParameterMap() &#123;</span><br><span class="line">        Map&lt;String, String[]&gt; parameterMap = super.getParameterMap();</span><br><span class="line"></span><br><span class="line">        LinkedHashMap map = new LinkedHashMap();</span><br><span class="line"></span><br><span class="line">        if (parameterMap != null) &#123;</span><br><span class="line">            for (String key : parameterMap.keySet()) &#123;</span><br><span class="line">                String[] values = parameterMap.get(key);</span><br><span class="line">                for (int i = 0; i &lt; values.length; i++) &#123;</span><br><span class="line">                    String value = values[i];</span><br><span class="line">                    if (!StrUtil.hasEmpty(value))&#123;</span><br><span class="line">                        value=HtmlUtil.filter(value);</span><br><span class="line">                    &#125;</span><br><span class="line">                    values[i]=value;</span><br><span class="line">                &#125;</span><br><span class="line">                map.put(key, values);</span><br><span class="line">            &#125;</span><br><span class="line">       &#125;</span><br><span class="line">        return map;</span><br><span class="line">    &#125;</span><br><span class="line">    @Override</span><br><span class="line">    public String getHeader(String name) &#123;</span><br><span class="line">        String value = super.getHeader(name);</span><br><span class="line">        if (!StrUtil.hasEmpty(value))&#123;</span><br><span class="line">            value=HtmlUtil.filter(value);</span><br><span class="line">        &#125;</span><br><span class="line">        return value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public ServletInputStream getInputStream() throws IOException &#123;</span><br><span class="line">        InputStream in= super.getInputStream();</span><br><span class="line">        InputStreamReader reader=new InputStreamReader(in, Charset.forName(&quot;UTF-8&quot;));</span><br><span class="line">        BufferedReader buffer=new BufferedReader(reader);</span><br><span class="line">        StringBuffer body=new StringBuffer();</span><br><span class="line">        String line=buffer.readLine();</span><br><span class="line">        while(line!=null)&#123;</span><br><span class="line">            body.append(line);</span><br><span class="line">            line=buffer.readLine();</span><br><span class="line">        &#125;</span><br><span class="line">        buffer.close();</span><br><span class="line">        reader.close();</span><br><span class="line">        in.close();</span><br><span class="line">        Map&lt;String,Object&gt; map= JSONUtil.parseObj(body.toString());</span><br><span class="line">        Map&lt;String,Object&gt; result=new LinkedHashMap&lt;&gt;();</span><br><span class="line">        for(String key:map.keySet())&#123;</span><br><span class="line">            Object val=map.get(key);</span><br><span class="line">            if(val instanceof String)&#123;</span><br><span class="line">                if(!StrUtil.hasEmpty(val.toString()))&#123;</span><br><span class="line">                    result.put(key,HtmlUtil.filter(val.toString()));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            else &#123;</span><br><span class="line">                result.put(key,val);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        String json=JSONUtil.toJsonStr(result);</span><br><span class="line">        ByteArrayInputStream bain=new ByteArrayInputStream(json.getBytes());</span><br><span class="line">        return new ServletInputStream() &#123;</span><br><span class="line">            @Override</span><br><span class="line">            public int read() throws IOException &#123;</span><br><span class="line">                return bain.read();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            @Override</span><br><span class="line">            public boolean isFinished() &#123;</span><br><span class="line">                return false;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            @Override</span><br><span class="line">            public boolean isReady() &#123;</span><br><span class="line">                return false;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            @Override</span><br><span class="line">            public void setReadListener(ReadListener readListener) &#123;</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></pre></td></tr></table></figure><script>alert('这就是被xss攻击的展示')</script>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Swagger搭建RESTAPI</title>
    <link href="http://example.com/posts/b23a516a.html"/>
    <id>http://example.com/posts/b23a516a.html</id>
    <published>2024-08-02T12:52:02.000Z</published>
    <updated>2024-08-02T15:45:21.202Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h3 id="配置Swagger"><a href="#配置Swagger" class="headerlink" title="配置Swagger"></a>配置Swagger</h3><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240802210458.png"></p><p>集成JWT令牌后，之后调用web方法时，都需要带着令牌。那么就必须要去上传令牌字符串儿。那么就必须要告诉Swagger，提交的请求里边哪一个参数是上传的令牌字符串儿，</p><p>需要去创建一个list对象。在里边呢，这个泛型是ApiKEY这样类型的一个对象，那么这个对象里面封装的就是告诉给swagger请求里边哪一个参数是提交上来的令牌字符串儿。把这个对象呢放在list集合里边。对这个list集合再次做一下封装，封装成一个认证的数组，这个认证数组对象呢，还要再次经过这个封装，封装成一个reference对象。放到另外的一个list集合里边。这个list集合还要再次进行封装。封装成一个context上下文儿对象，然后封装到另外的一个list里边，那么这个最后的list才是我们要用到的list。</p><ul><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></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;io.springfox&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;springfox-swagger2&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;2.9.2&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;io.springfox&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;springfox-swagger-ui&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;2.9.2&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure><ul><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><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">package com.example.emos.wx.config;</span><br><span class="line"></span><br><span class="line">import io.swagger.annotations.ApiOperation;</span><br><span class="line">import org.springframework.context.annotation.Bean;</span><br><span class="line">import org.springframework.context.annotation.Configuration;</span><br><span class="line">import springfox.documentation.builders.ApiInfoBuilder;</span><br><span class="line">import springfox.documentation.builders.PathSelectors;</span><br><span class="line">import springfox.documentation.builders.RequestHandlerSelectors;</span><br><span class="line">import springfox.documentation.service.ApiInfo;</span><br><span class="line">import springfox.documentation.service.ApiKey;</span><br><span class="line">import springfox.documentation.service.AuthorizationScope;</span><br><span class="line">import springfox.documentation.service.SecurityReference;</span><br><span class="line">import springfox.documentation.spi.DocumentationType;</span><br><span class="line">import springfox.documentation.spi.service.contexts.SecurityContext;</span><br><span class="line">import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;</span><br><span class="line">import springfox.documentation.spring.web.plugins.Docket;</span><br><span class="line">import springfox.documentation.swagger2.annotations.EnableSwagger2;</span><br><span class="line"></span><br><span class="line">import java.util.ArrayList;</span><br><span class="line">import java.util.List;</span><br><span class="line"></span><br><span class="line">// 配置Swagger文档生成的注解</span><br><span class="line">@Configuration</span><br><span class="line">// 启用Swagger2</span><br><span class="line">@EnableSwagger2</span><br><span class="line">public class SwaggerConfig &#123;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 创建RESTful API的Docket实例</span><br><span class="line">     *</span><br><span class="line">     * @return Docket实例</span><br><span class="line">     */</span><br><span class="line">    @Bean</span><br><span class="line">    public Docket createRestApi() &#123;</span><br><span class="line">      Docket docket = new Docket(DocumentationType.SWAGGER_2);</span><br><span class="line">        // 构建API信息</span><br><span class="line">        ApiInfoBuilder Builder = new ApiInfoBuilder();</span><br><span class="line">        Builder.title(&quot;api接口文档&quot;);</span><br><span class="line">        ApiInfo apiInfo = Builder.build();</span><br><span class="line">        docket.apiInfo(apiInfo);</span><br><span class="line"></span><br><span class="line">        // 选择API</span><br><span class="line">        ApiSelectorBuilder selectorBuilder = docket.select();</span><br><span class="line">        // 选择所有路径</span><br><span class="line">        selectorBuilder.paths(PathSelectors.any());</span><br><span class="line">        // 选择带有ApiOperation注解的方法</span><br><span class="line">        //使用@ApiOperation的方法会被提取到REST API中</span><br><span class="line">        selectorBuilder.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class));</span><br><span class="line">        docket = selectorBuilder.build();</span><br><span class="line"></span><br><span class="line">        /*</span><br><span class="line">      // 下面的语句是开启对JWT的支持，当用户用Swagger调用受JWT认证保护的方法，</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">        ApiKey apiKey = new ApiKey(&quot;token&quot;, &quot;token&quot;, &quot;header&quot;);</span><br><span class="line">        List&lt;ApiKey&gt; apiKeyList = new ArrayList&lt;&gt;();</span><br><span class="line">      //规定用户需要输入什么参数</span><br><span class="line">        apiKeyList.add(apiKey);</span><br><span class="line">        docket.securitySchemes(apiKeyList);</span><br><span class="line"></span><br><span class="line">        // 设置授权范围</span><br><span class="line">        //如果用户JWT认证通过，则在Swagger中全局有效</span><br><span class="line">        AuthorizationScope scope = new AuthorizationScope(&quot;global&quot;, &quot;accessEverything&quot;);</span><br><span class="line">        AuthorizationScope[] scopes = &#123;scope&#125;;</span><br><span class="line">        //存储令牌和作用域</span><br><span class="line">        SecurityReference reference = new SecurityReference(&quot;token&quot;, scopes);</span><br><span class="line">        List refList = new ArrayList();</span><br><span class="line">        refList.add(reference);</span><br><span class="line">        // 设置安全上下文</span><br><span class="line">        SecurityContext context = SecurityContext.builder().securityReferences(refList).build();</span><br><span class="line">        List cxtList = new ArrayList();</span><br><span class="line">        cxtList.add(context);</span><br><span class="line">        docket.securityContexts(cxtList);</span><br><span class="line"></span><br><span class="line">      return docket;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><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></pre></td><td class="code"><pre><span class="line">@RestController</span><br><span class="line">@RequestMapping(&quot;/test&quot;)</span><br><span class="line">@Api(&quot;测试接口&quot;)</span><br><span class="line">public class testcontroller &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   @GetMapping(&quot;/sayHello&quot;)</span><br><span class="line">   @ApiOperation(&quot;测试接口&quot;)</span><br><span class="line">    public R sayHello()</span><br><span class="line">    &#123;</span><br><span class="line">        return R.ok().put(&quot;msg&quot;,&quot;hello&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>设置静态IP</title>
    <link href="http://example.com/posts/8023e37.html"/>
    <id>http://example.com/posts/8023e37.html</id>
    <published>2024-08-02T09:56:52.000Z</published>
    <updated>2024-08-02T15:45:21.207Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><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">cd /etc/sysconfig/network-scripts/</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></pre></td><td class="code"><pre><span class="line">cp -rp /etc/sysconfig/network-scripts/ifcfg-enp0s3 /etc/sysconfig/network-scripts/ifcfg-enp0s3.bak</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></pre></td><td class="code"><pre><span class="line">vi /etc/sysconfig/network-scripts/ifcfg-enp0s3</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><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">TYPE=&quot;Ethernet&quot;</span><br><span class="line">PROXY_METHOD=&quot;none&quot;</span><br><span class="line">BROWSER_ONLY=&quot;no&quot;</span><br><span class="line">BOOTPROTO=&quot;static&quot;</span><br><span class="line"></span><br><span class="line">IPADDR=&quot;172.21.208.200&quot;</span><br><span class="line">NETMASK=&quot;255.255.252.0&quot;</span><br><span class="line">GATEWAY=&quot;172.21.208.1&quot;</span><br><span class="line">DNS1=&quot;8.8.8.8&quot;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">DEFROUTE=&quot;yes&quot;</span><br><span class="line">IPV4_FAILURE_FATAL=&quot;no&quot;</span><br><span class="line">IPV6INIT=&quot;yes&quot;</span><br><span class="line">IPV6_AUTOCONF=&quot;yes&quot;</span><br><span class="line">IPV6_DEFROUTE=&quot;yes&quot;</span><br><span class="line">IPV6_FAILURE_FATAL=&quot;no&quot;</span><br><span class="line">IPV6_ADDR_GEN_MODE=&quot;stable-privacy&quot;</span><br><span class="line">NAME=&quot;enp0s3&quot;</span><br><span class="line">UUID=&quot;22fcffef-ba52-450c-a3a2-422f744fe54d&quot;</span><br><span class="line">DEVICE=&quot;enp0s3&quot;</span><br><span class="line">ONBOOT=&quot;yes&quot;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>打开dos命令行, 输入ipconfig &#x2F;all 可以查看主机中的网络配置, 如下</p><p>换成自己的网段</p><p><img src="http://www.1330.cn/d/20211016/9630bfd831b53eb8b6660fdbed8151ed.gif"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Vue</title>
    <link href="http://example.com/posts/f8e09374.html"/>
    <id>http://example.com/posts/f8e09374.html</id>
    <published>2024-07-27T12:27:50.000Z</published>
    <updated>2024-08-02T15:45:21.203Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="前端" scheme="http://example.com/categories/%E5%89%8D%E7%AB%AF/"/>
    
    <category term="框架" scheme="http://example.com/categories/%E5%89%8D%E7%AB%AF/%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="前端框架" scheme="http://example.com/tags/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>markdown文件编译</title>
    <link href="http://example.com/posts/d2475ec3.html"/>
    <id>http://example.com/posts/d2475ec3.html</id>
    <published>2024-07-18T07:59:32.000Z</published>
    <updated>2024-07-18T08:09:29.585Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="markdown文件编译"><a href="#markdown文件编译" class="headerlink" title="markdown文件编译"></a>markdown文件编译</h1><h2 id="标准开头"><a href="#标准开头" class="headerlink" title="标准开头"></a>标准开头</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></pre></td><td class="code"><pre><span class="line">title: 标题</span><br><span class="line">date: 时间</span><br><span class="line">tags: 标签</span><br><span class="line">categories: 分类</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">categories:</span><br><span class="line">- [学习,html]</span><br><span class="line">- [学习,http]</span><br><span class="line">效果如本博客所示</span><br><span class="line"></span><br></pre></td></tr></table></figure><hr><h2 id="文章摘要"><a href="#文章摘要" class="headerlink" title="文章摘要"></a>文章摘要</h2><p>英文的&gt;是文章摘要，一个回车继续写，2个回车退出该次编辑</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">&gt; +文章概要</span><br></pre></td></tr></table></figure><p>例如：</p><blockquote><p>文章摘要</p></blockquote><hr><h2 id="复选框"><a href="#复选框" class="headerlink" title="复选框"></a>复选框</h2><p>-[]内容，在横岗后面加空格，在中括号中加空格。</p><p>例如</p><ul><li><input disabled="" type="checkbox"> </li></ul><hr><h2 id="删除线"><a href="#删除线" class="headerlink" title="删除线"></a>删除线</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">方法一：~~内容~~</span><br><span class="line"> </span><br><span class="line">方法二：~~内容~   </span><br></pre></td></tr></table></figure><p>示例：</p><p><del>内容</del></p><hr><h2 id="划横线和代码块"><a href="#划横线和代码块" class="headerlink" title="划横线和代码块"></a>划横线和代码块</h2><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><h2 id="latex数学公式编辑器"><a href="#latex数学公式编辑器" class="headerlink" title="latex数学公式编辑器"></a>latex数学公式编辑器</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">$$</span><br><span class="line">里面插入latex代码</span><br><span class="line">$$</span><br><span class="line">[在线latex工具](https://www.texpage.com/)</span><br></pre></td></tr></table></figure><h2 id="表格"><a href="#表格" class="headerlink" title="表格"></a>表格</h2><p>左对齐</p><blockquote><p>:———-</p></blockquote><p>右对齐</p><blockquote><p>———-:</p></blockquote><p>居中对齐</p><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></pre></td><td class="code"><pre><span class="line">| 课程表 | 星期一  |  星期二  |  星期三  | 星期四  |  星期五  |</span><br><span class="line">| :----: | :-----: | :------: | :------: | :-----: | :------: |</span><br><span class="line">|  上午  |  Math   | Chinese  |  Music   |  Math   | Chinese  |</span><br><span class="line">|  下午  | Chinese |    PE    |   Math   | English | Computer |</span><br><span class="line">| 晚自习 | English | Computer | Computer |  Math   | Chinese  |</span><br><span class="line"></span><br></pre></td></tr></table></figure><table><thead><tr><th align="center">课程表</th><th align="center">星期一</th><th align="center">星期二</th><th align="center">星期三</th><th align="center">星期四</th><th align="center">星期五</th></tr></thead><tbody><tr><td align="center">上午</td><td align="center">Math</td><td align="center">Chinese</td><td align="center">Music</td><td align="center">Math</td><td align="center">Chinese</td></tr><tr><td align="center">下午</td><td align="center">Chinese</td><td align="center">PE</td><td align="center">Math</td><td align="center">English</td><td align="center">Computer</td></tr><tr><td align="center">晚自习</td><td align="center">English</td><td align="center">Computer</td><td align="center">Computer</td><td align="center">Math</td><td align="center">Chinese</td></tr></tbody></table>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>jmeter</title>
    <link href="http://example.com/posts/808e762c.html"/>
    <id>http://example.com/posts/808e762c.html</id>
    <published>2024-07-18T07:54:50.000Z</published>
    <updated>2024-07-18T17:38:51.584Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="jmeter"><a href="#jmeter" class="headerlink" title="jmeter"></a>jmeter</h1><h2 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</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">缺点：</span><br><span class="line">1. 不支持IP欺骗</span><br><span class="line">2. 使用JMeter无法验证JS程序，也无法验证页面UI，所以要和Selenium配合来完成Web2.0应用的测试</span><br></pre></td></tr></table></figure><h2 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h2><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/20240718173655.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718173741.png"></p><h2 id="线程组"><a href="#线程组" class="headerlink" title="线程组"></a>线程组</h2><p>进 程: 正在运行的程序<br>线 程: 是进程中的执行线索<br>线程组: 进程中有许多线程，为了方便管理，可以对线程按照性质分组，分组的结果就是线程组</p><p>三者关系，一个进程可以包含多个线程组，一个线程组可以包含多个线程</p><h2 id="并发执行"><a href="#并发执行" class="headerlink" title="并发执行"></a>并发执行</h2><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718173816.png"></p><h2 id="jmeter里俩个特殊的线程组"><a href="#jmeter里俩个特殊的线程组" class="headerlink" title="jmeter里俩个特殊的线程组"></a>jmeter里俩个特殊的线程组</h2><ul><li>setUp线程组：最优先执行的线程组</li><li>tearDown线程组：最后执行的线程组</li></ul><h2 id="线程组常用属性"><a href="#线程组常用属性" class="headerlink" title="线程组常用属性"></a>线程组常用属性</h2><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter20240718173027.png"></p><ul><li>线程数：模拟的用户个数</li><li>ramp：程序的准备时间</li><li>循环次数：每个线程执行的次数</li></ul><h2 id="http请求默认值"><a href="#http请求默认值" class="headerlink" title="http请求默认值"></a>http请求默认值</h2><p>http请求默认值：被复用的内容的封装</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718174618.png"></p><h2 id="信息头管理器"><a href="#信息头管理器" class="headerlink" title="信息头管理器"></a>信息头管理器</h2><p>新增修改实现时提交的数据是 JSON 格式的，需声明提交的数据的内容类型：</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718174812.png"></p><p>后端传数据的时候要在这声明提交的数据的内容类型才知道是json</p><h2 id="参数化"><a href="#参数化" class="headerlink" title="参数化"></a>参数化</h2><p>定义：动态的获取、设置或生成数据，是一种由程序驱动代替人工驱动的数据设计方案，提高脚本的编写效率以及编写质量</p><p>以下四种方式实现参数化：</p><p>1、用户定义的变量<br>2、CSV 数据文件设置<br>3、用户参数<br>4、函数</p><h3 id="参数化–用户定义的变量"><a href="#参数化–用户定义的变量" class="headerlink" title="参数化–用户定义的变量"></a>参数化–用户定义的变量</h3><p>调用格式: ${变量名}</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718175727.png"></p><p>请求路径： {myPath}</p><h3 id="参数化–CSV数据文件设置"><a href="#参数化–CSV数据文件设置" class="headerlink" title="参数化–CSV数据文件设置"></a>参数化–CSV数据文件设置</h3><p>CSV ：逗号分隔值，是一种简洁且常见的数据存储格式，存储语法如下图所示</p><p>实现步骤:<br>1、使用 CSV 文件存储测试数据<br>2、编写被复用的学院新增脚本模板<br>注意2: 编码集使用 UTF-8 无 BOM 格式<br>3、关联脚本与数据(将文件数据导入脚本)</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718180454.png"></p><p>变量名称 : 脚本中的每个字段与变量名称相对应</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718180850.png"></p><h3 id="参数化–用户参数"><a href="#参数化–用户参数" class="headerlink" title="参数化–用户参数"></a>参数化–用户参数</h3><p>实现步骤:<br>1、编写被复用的学院新增脚本模板<br>2、使用 用户参数存储测试数据<br>3、将数据导入脚本模板<br>4、设置执行次数</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718181431.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718181351.png"></p><h2 id="参数化–函数"><a href="#参数化–函数" class="headerlink" title="参数化–函数"></a>参数化–函数</h2><p>常见函数：<br>_counter 计数器函数 TRUE(每个用户都有自己的计数器) FALSE(所有用户共用一个计数器)<br>_Random 随机数函数 参数1：取值范围最小值(包含) 参数2：取值范围最大值(包含)<br>_time 获取当前时间的函数 无参: 获取的是距离 1970&#x2F;01&#x2F;01 00:00:00 的毫秒值<br>参数</p><p> <img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718191128.png"></p><h2 id="直连数据库"><a href="#直连数据库" class="headerlink" title="直连数据库"></a>直连数据库</h2><p>通过直连数据库让程序代替接口访问数据库，如果二者预期结果不一致，就找到了程序缺陷。<br>获取某条学院的名字，放在百度搜索：<br>1、Jmeter 不具备直连数据库功能，必须整合第三方(jar包)实现<br>2、配置数据库的连接<br>3、通过JDBC Request请求向数据库发送 SQL语句并接收提取响应结果<br>4、结果获取规则可以通过 Debug Sampler 组件查看<br>5、将提取到的响应结果，在百度上</p><ul><li>添加jar包</li></ul><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718215552.png"></p><ul><li>配置数据库</li></ul><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718215630.png"></p><ul><li>编写sql语句</li></ul><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718215804.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718215910.png"></p><ul><li>获取结果集通过Debug Sampler组件查看</li></ul><p>​<img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718220417.png"></p><ul><li>百度显示</li></ul><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718220853.png"></p><h2 id="断言"><a href="#断言" class="headerlink" title="断言"></a>断言</h2><ul><li><p>断言：让程序代替人工判断响应结果是否符合预期</p></li><li><p>分类：</p><ul><li><p>响应断言 &#x3D; 断言状态码和响应体</p></li><li><p>大小断言 &#x3D; 判断响应内容的字节长度</p></li><li><p>断言持续时间 &#x3D; 判断响应时间</p></li></ul></li><li><p>步骤：</p><ul><li>1、按照之前的实现编写测试脚本</li><li>2、为被判断的取样器添加断言组件</li><li>3、直接运行查看结果断言通过: 无提示</li><li>断言失败: 给出错误</li></ul></li></ul><h2 id="响应断言"><a href="#响应断言" class="headerlink" title="响应断言"></a>响应断言</h2><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718221335.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718221544.png"></p><h2 id="大小断言"><a href="#大小断言" class="headerlink" title="大小断言"></a>大小断言</h2><p>​判断结果数据多少</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240718221641.png"></p><p>注：响应码是三个字节 ! </p><h2 id="逻辑控制器"><a href="#逻辑控制器" class="headerlink" title="逻辑控制器"></a>逻辑控制器</h2><p>通过参数化可以实现单个接口的功能测试，而接口测试过程中，除了单个接口的功能测试之外，还会测试接口业务实现，所谓业务，就是一套完整的业务逻辑或流程，这就必须要使用到逻辑控制和关联。</p><h3 id="if逻辑控制器"><a href="#if逻辑控制器" class="headerlink" title="if逻辑控制器"></a>if逻辑控制器</h3><p>需求1:测试计划中定义一个 http 请求访问传智播客官网，但是该请求不是无条件执行的，声明一个用户定义的变量，如果变量是 itcast 才执行，否则就不执行<br>1、搭框架，测试计划，线程组，结果树，声明一个用户定义的变量<br>2、核心:添加 if 控制器，子级添加取样器 (和之前实现不同，控制器和取样器存在父子级关系)</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719001401.png"></p><p><img src="E:\blog\source_posts\jmeter.assets\20240719001551.png"></p><blockquote><p> 如果在用户定义变量中设置  名称为myComp值为 itcast 那么请求可以执行</p></blockquote><h3 id="foreach逻辑控制器"><a href="#foreach逻辑控制器" class="headerlink" title="foreach逻辑控制器"></a>foreach逻辑控制器</h3><p>需求2:有一组关键字 [hello,python,测试] (使用用户定义的变量存储)要依次取出，并在百度搜索<br>1、搭框架，测试计划，线程组，结果树，声明一个用户定义的变量,存储一组数据<br>2、添加 forEach 控制器，子级添加取样器 (和之前实现不同，控制器和取样器存在父子级关系)<br>3、百度搜索关键字</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719002211.png"></p><p>配置原件中设置自定义变量</p><table><thead><tr><th align="center">名称</th><th align="center">值</th></tr></thead><tbody><tr><td align="center">name_1</td><td align="center">java</td></tr><tr><td align="center">name_2</td><td align="center">c</td></tr><tr><td align="center">name_3</td><td align="center">py</td></tr></tbody></table><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719002236.png"></p><blockquote><p>请求路径中含有${ele}</p></blockquote><h3 id="循环逻辑控制器"><a href="#循环逻辑控制器" class="headerlink" title="循环逻辑控制器"></a>循环逻辑控制器</h3><p>需求3:循环访问学生管理系统10次<br>实现:<br>1、搭框架，测试计划，线程组，结果树<br>2、添加循环控制器，子级添加取样器 (和之前实现不同，控制器和取样器存在父子级关系)</p><blockquote><p>局部循环罢了</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719004037.png"></p><h2 id="业务之间的关联"><a href="#业务之间的关联" class="headerlink" title="业务之间的关联"></a>业务之间的关联</h2><p><strong>关联: 上一个请求的响应结果和下一个请求的数据有关系</strong></p><blockquote><p>比如，要删除数据要先查出来才能删除</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719004330.png"></p><h3 id="关联-xpath提取器"><a href="#关联-xpath提取器" class="headerlink" title="关联-xpath提取器"></a>关联-xpath提取器</h3><blockquote><p>获取标签内容</p></blockquote><p>需求:两个http请求，请求A访问传智播客官网，请求B访问百度 ，请求A将传智播客官网源码中的 title 标签的值取出，传递给请求B，在请求B中作为关键字搜索这个 title 值<br>步骤：<br>1、搭框架,编写两个请求，传智播客 + 百度搜索<br>2、核心: 取出传智播客页面源码的 title 值<br>3、传递给百度：${变量名} 的方式传值</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719005319.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719005042.png"></p><blockquote><p>提取title标签内容，如果请求成功，就会把title标签中的内容放到myTitle变量中</p></blockquote><h3 id="关联-正则表达式提取器"><a href="#关联-正则表达式提取器" class="headerlink" title="关联-正则表达式提取器"></a>关联-正则表达式提取器</h3><p>需求:两个请求,请时求A查询所有学院信息，请求B访问百度，从请求A中提取出第一个学院的学院名称，把名称放在百度上搜索<br>步骤：<br>1、搭框架,编写两个请求，查询所有学院信息 + 百度搜索<br>2、核心:从学院查询中提取学院名称<br>3、传递给百度，调用格式: ${变量名}</p><blockquote><p> 建议: 如果从标签文档提取数据建议使用 XPath 提取器，如果从非标签文档提取数据建议使用正则表达式提取器</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719010039.png"></p><h2 id="跨线程组关联"><a href="#跨线程组关联" class="headerlink" title="跨线程组关联"></a>跨线程组关联</h2><p>变量作用域局限于当前线程组，其他线程组不可以直接调用。可以将请求A中提取的结果导出到公共空间(可以被不同线程组共享),请求B再从公开空间调用该变量，相当于全局变量。</p><p>步骤：<br>1、将请求A的数据导出到公共空间( _setProperty)<br>2、把代码放在beanshell取样器中<br>3、请求B从公共空间调用数据 (__property)</p><blockquote><p>选择函数助手</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719011331.png"></p><blockquote><p>放</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719011423.png"></p><blockquote><p>拿</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719011534.png"></p><h2 id="性能测试"><a href="#性能测试" class="headerlink" title="性能测试"></a>性能测试</h2><p>模拟各种正常的、峰值的测试环境，检测程序的各项性能指标是否能够达标 更</p><h3 id="高并发"><a href="#高并发" class="headerlink" title="高并发"></a>高并发</h3><p>JMeter 中内置了 定时器，可以实现时间模式相关的性能测试<br>需求1:同一时刻 100 个同学去访问学生管理系统的查询所有学院信息功能,统计高并发情况下平均响应时间以及错误率(高并发)<br>1、搭框架,测试计划，线程组，取样器，结果树(局限性),指定线程组的线程数属性值为 100<br>2、添加定时器 synchronizing timer(集合点组件)<br>3、运行并查看结果查看：聚合报告组件,可以对结果汇总分析</p><h4 id="同步定时器"><a href="#同步定时器" class="headerlink" title="同步定时器"></a>同步定时器</h4><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719012458.png"></p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719012610.png"></p><blockquote><p>超时时间必须要设置，防止出现死等状态</p></blockquote><blockquote><p>将结果树监听器替换成聚合报告</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719012737.png"></p><h3 id="高频率"><a href="#高频率" class="headerlink" title="高频率"></a>高频率</h3><p>需求2:一个用户以 20QPS ( &#x3D;&#x3D; 20 次&#x2F;s) 的频率访问学生管理系统服务器，持续15秒，统计服务器的平均响应时间<br>QPS: Query per Seconds 每秒查询数(查询率),每秒访问多少次服务器<br>1、搭框架，测试计划，线程组，取样器，聚合报告,根据题干计算数据:<br>循环次数 &#x3D; 访问频率 * 持续时间<br>2、添加QPS访问频率控制的相关组件：<br>每分钟访问次数 &#x3D; 访问频率 * 60</p><blockquote><p>设置常量吞吐量定时器</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719013043.png"></p><blockquote><p>设置循环次数，频率*时间  （20qps * 15s&#x3D;300次）</p></blockquote><h2 id="分布式"><a href="#分布式" class="headerlink" title="分布式"></a>分布式</h2><blockquote><p>多台机协作，以集群的方式完成测试任务，可以提高测试效率。</p></blockquote><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719013603.png"></p><p>环境搭建：<br>1、不同的测试机上安装 Jmeter<br>2、配置基础环境(统一操作系统、JDK、Jmeter …. )<br>3、核心: 控制机如何与执行机通信? 关键点：端口号<br>4、控制机中设置执行机的 IP<br>%JMETER_HOME%&#x2F;bin&#x2F;jmeter.properties —-&gt; remote_hosts&#x3D;执行机A的IP:端口号, 执行机B的IP:端口号, …..</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719013752.png"></p><p>3-3、控制机和执行机都得设置远程访问相关属性：<br>server.rmi.ssl.disable&#x3D;true</p><p><img src="https://raw.githubusercontent.com/SuoXiuYuan/typora_img/master/images/jmeter/20240719013803.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="测压" scheme="http://example.com/categories/%E6%B5%8B%E5%8E%8B/"/>
    
    
    <category term="压力测试" scheme="http://example.com/tags/%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>后端学习路线</title>
    <link href="http://example.com/posts/bae03965.html"/>
    <id>http://example.com/posts/bae03965.html</id>
    <published>2024-07-17T16:40:18.000Z</published>
    <updated>2024-07-18T08:32:36.123Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="Java后端的学习路线"><a href="#Java后端的学习路线" class="headerlink" title="Java后端的学习路线"></a><strong>Java后端的学习路线</strong></h1><p>注：原创来自于晋中信息学院双体软件精英产业学院，本人二次修改并非原创</p><h2 id="第一部分：java基础"><a href="#第一部分：java基础" class="headerlink" title="第一部分：java基础"></a>第一部分：java基础</h2><ul><li><h3 id="JavaSE"><a href="#JavaSE" class="headerlink" title="JavaSE"></a>JavaSE</h3><p><a href="https://www.bilibili.com/video/BV1Rx411876f/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">https://www.bilibili.com/video/BV1Rx411876f/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544</a></p></li><li><h3 id="MySQL"><a href="#MySQL" class="headerlink" title="MySQL"></a>MySQL</h3></li></ul><p>​<a href="https://www.bilibili.com/video/BV1Vy4y1z7EX">https://www.bilibili.com/video/BV1Vy4y1z7EX</a></p><ul><li><h3 id="JDBC"><a href="#JDBC" class="headerlink" title="JDBC"></a>JDBC</h3><p><a href="https://www.bilibili.com/video/BV1Bt41137iB">https://www.bilibili.com/video/BV1Bt41137iB</a></p><p>完成后写一个飞机大战大作业</p><h3 id="飞机大战"><a href="#飞机大战" class="headerlink" title="飞机大战"></a>飞机大战</h3><p><a href="https://www.bilibili.com/video/BV1oz4y1a7xU">https://www.bilibili.com/video/BV1oz4y1a7xU</a></p></li></ul><h2 id="第二部分：数据结构"><a href="#第二部分：数据结构" class="headerlink" title="第二部分：数据结构"></a>第二部分：数据结构</h2><ul><li><h3 id="韩顺平版"><a href="#韩顺平版" class="headerlink" title="韩顺平版"></a>韩顺平版</h3></li></ul><p>​<a href="https://www.bilibili.com/video/BV1E4411H73v">https://www.bilibili.com/video/BV1E4411H73v</a></p><ul><li><h3 id="黑马"><a href="#黑马" class="headerlink" title="黑马"></a>黑马</h3><p><a href="https://www.bilibili.com/video/BV1oz4y1a7xU">https://www.bilibili.com/video/BV1oz4y1a7xU</a></p></li><li><h3 id="左程云版-有点难度不建议初学者，推荐算法比赛的人听"><a href="#左程云版-有点难度不建议初学者，推荐算法比赛的人听" class="headerlink" title="左程云版(有点难度不建议初学者，推荐算法比赛的人听)"></a>左程云版(有点难度不建议初学者，推荐算法比赛的人听)</h3><p>(<a href="https://space.bilibili.com/8888480">https://space.bilibili.com/8888480</a>)</p></li></ul><hr><h2 id="第三部分：web前端"><a href="#第三部分：web前端" class="headerlink" title="第三部分：web前端"></a>第三部分：web前端</h2><ul><li><h3 id="HTML5-CSS3"><a href="#HTML5-CSS3" class="headerlink" title="HTML5+CSS3"></a>HTML5+CSS3</h3><p><a href="https://www.bilibili.com/video/BV1XJ411X7Ud/">https://www.bilibili.com/video/BV1XJ411X7Ud/</a></p></li><li><h3 id="JavaScript"><a href="#JavaScript" class="headerlink" title="JavaScript"></a>JavaScript</h3></li></ul><p>​<a href="https://www.bilibili.com/video/av62653534/">https://www.bilibili.com/video/av62653534/</a></p><ul><li><h3 id="jquery"><a href="#jquery" class="headerlink" title="jquery"></a><strong>jquery</strong></h3><p><a href="https://www.bilibili.com/video/BV1pt411H7D6/?spm_id_from=333.337.search-card.all.click%EF%BC%88%E9%BB%91%E9%A9%AC%EF%BC%89">https://www.bilibili.com/video/BV1pt411H7D6/?spm_id_from=333.337.search-card.all.click（黑马）</a></p><p><a href="https://www.bilibili.com/video/BV1ts411E7ag/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89">https://www.bilibili.com/video/BV1ts411E7ag/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（尚硅谷）</a></p><p><a href="https://www.bilibili.com/video/BV1Jg4y1B7n4/?spm_id_from=333.337.search-card.all.click%EF%BC%88%E5%8A%A8%E5%8A%9B%E8%8A%82%E7%82%B9%EF%BC%89">https://www.bilibili.com/video/BV1Jg4y1B7n4/?spm_id_from=333.337.search-card.all.click（动力节点）</a></p></li></ul><h2 id="第四部分：框架总结"><a href="#第四部分：框架总结" class="headerlink" title="第四部分：框架总结"></a>第四部分：框架总结</h2><ul><li><h3 id="Maven框架"><a href="#Maven框架" class="headerlink" title="Maven框架"></a><a href="https://www.bilibili.com/video/BV1dp4y1Q7Hf/?spm_id_from=333.337.search-card.all.click&vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">Maven框架</a></h3></li><li><h3 id="JavaWeb（三选一）"><a href="#JavaWeb（三选一）" class="headerlink" title="JavaWeb（三选一）"></a>JavaWeb（三选一）</h3><p><a href="https://www.bilibili.com/video/BV1Y7411K7zz?spm_id_from=333.337.search-card.all.click%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89">https://www.bilibili.com/video/BV1Y7411K7zz?spm_id_from=333.337.search-card.all.click（尚硅谷）</a></p><p><a href="https://www.bilibili.com/video/BV1Z3411C7NZ/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E5%8A%A8%E5%8A%9B%E8%8A%82%E7%82%B9%E8%80%81%E6%9D%9C%E7%9A%84%EF%BC%89">https://www.bilibili.com/video/BV1Z3411C7NZ/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（动力节点老杜的）</a></p><p><a href="https://www.bilibili.com/video/BV1Qf4y1T7Hx/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E9%BB%91%E9%A9%AC%E7%9A%84%EF%BC%89">https://www.bilibili.com/video/BV1Qf4y1T7Hx/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（黑马的）</a></p></li><li><h3 id="Git"><a href="#Git" class="headerlink" title="Git"></a><a href="%5B%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98Git%E5%85%A8%E5%A5%97%E6%95%99%E7%A8%8B%EF%BC%8C%E5%AE%8C%E6%95%B4%E7%9A%84git%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7%E6%95%99%E7%A8%8B%EF%BC%8C%E4%B8%80%E5%A5%97%E7%B2%BE%E9%80%9Agit_%E5%93%94%E5%93%A9%E5%93%94%E5%93%A9_bilibili%5D(https://www.bilibili.com/video/BV1MU4y1Y7h5/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544)">Git</a></h3></li><li><h3 id="SSM框架整合"><a href="#SSM框架整合" class="headerlink" title="SSM框架整合"></a><a href="https://www.bilibili.com/video/BV1WZ4y1P7Bp/?spm_id_from=333.337.search-card.all.click">SSM框架整合</a></h3></li><li><h3 id="SSM项目"><a href="#SSM项目" class="headerlink" title="SSM项目"></a><a href="%5B%E5%8A%A8%E5%8A%9B%E8%8A%82%E7%82%B9java%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%7CSpring+Mybatis+Springmvc%E6%A1%86%E6%9E%B6SSM%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%E6%95%B4%E5%90%88-%E3%80%90CRM%E5%AE%A2%E6%88%B7%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E3%80%91_%E5%93%94%E5%93%A9%E5%93%94%E5%93%A9_bilibili%5D(https://www.bilibili.com/video/BV1tZ4y1d7kg/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2)">SSM项目</a></h3></li><li><h3 id="SpringBoot（三选一）"><a href="#SpringBoot（三选一）" class="headerlink" title="SpringBoot（三选一）"></a>SpringBoot（三选一）</h3><p><a href="https://www.bilibili.com/video/BV19K4y1L7MT/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV19K4y1L7MT/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a> (尚硅谷)</p><p><a href="https://www.bilibili.com/video/BV15b4y1a7yG/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E9%BB%91%E9%A9%AC%EF%BC%89">https://www.bilibili.com/video/BV15b4y1a7yG/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（黑马）</a></p><p><a href="https://www.bilibili.com/video/BV1XQ4y1m7ex/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E5%8A%A8%E5%8A%9B%E8%8A%82%E7%82%B9%EF%BC%89">https://www.bilibili.com/video/BV1XQ4y1m7ex/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（动力节点）</a></p></li><li><h3 id="VUE-二选一"><a href="#VUE-二选一" class="headerlink" title="VUE(二选一)"></a>VUE(二选一)</h3><ul><li><p><a href="https://www.bilibili.com/video/BV1Zy4y1K7SH/?spm_id_from=333.337.search-card.all.click%E5%B0%9A%E7%A1%85%E8%B0%B7">https://www.bilibili.com/video/BV1Zy4y1K7SH/?spm_id_from=333.337.search-card.all.click尚硅谷</a></p></li><li><p><a href="https://www.bilibili.com/video/BV17h41137i4/?spm_id_from=333.337.search-card.all.click&vd_source=205b9aa791a13bdcc9e04b9d7d1e0544%E8%80%81%E6%9D%9C">https://www.bilibili.com/video/BV17h41137i4/?spm_id_from=333.337.search-card.all.click&amp;vd_source=205b9aa791a13bdcc9e04b9d7d1e0544老杜</a></p></li></ul></li><li><h3 id="SpringBoot项目"><a href="#SpringBoot项目" class="headerlink" title="SpringBoot项目"></a>SpringBoot项目</h3><ul><li><h6 id="苍穹外卖"><a href="#苍穹外卖" class="headerlink" title="苍穹外卖"></a>苍穹外卖</h6><h6 id="https-www-bilibili-com-video-BV1TP411v7v6-vd-source-205b9aa791a13bdcc9e04b9d7d1e0544"><a href="#https-www-bilibili-com-video-BV1TP411v7v6-vd-source-205b9aa791a13bdcc9e04b9d7d1e0544" class="headerlink" title="https://www.bilibili.com/video/BV1TP411v7v6/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544"></a><a href="https://www.bilibili.com/video/BV1TP411v7v6/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">https://www.bilibili.com/video/BV1TP411v7v6/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544</a></h6></li></ul></li></ul><h2 id="第五部分：分布式，微服务，并行架构"><a href="#第五部分：分布式，微服务，并行架构" class="headerlink" title="第五部分：分布式，微服务，并行架构"></a>第五部分：分布式，微服务，并行架构</h2><ul><li><h3 id="Linux"><a href="#Linux" class="headerlink" title="Linux"></a><strong>Linux</strong></h3><p><a href="https://www.bilibili.com/video/BV1Sv411r7vd/?spm_id_from=333.337.search-card.all.click%EF%BC%88%E9%9F%A9%E9%A1%BA%E5%B9%B3%E7%9A%84%EF%BC%8C%E8%AE%B2%E7%9A%84%E5%BE%88%E8%AF%A6%E7%BB%86%EF%BC%89">https://www.bilibili.com/video/BV1Sv411r7vd/?spm_id_from=333.337.search-card.all.click（韩顺平的，讲的很详细）</a></p></li><li><h2 id="springcloud"><a href="#springcloud" class="headerlink" title="springcloud"></a><a href="https://www.bilibili.com/video/BV1LQ4y127n4/?spm_id_from=333.337.search-card.all.click&vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">springcloud</a></h2></li><li><h3 id="Docker"><a href="#Docker" class="headerlink" title="Docker"></a><a href="https://www.bilibili.com/video/BV1HP4118797/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">Docker</a></h3></li><li><h3 id="Dubbo"><a href="#Dubbo" class="headerlink" title="Dubbo"></a><a href="https://www.bilibili.com/video/BV1VE411q7dX/">Dubbo</a></h3></li><li><h3 id="Zookeeper"><a href="#Zookeeper" class="headerlink" title="Zookeeper"></a><a href="https://www.bilibili.com/video/BV1M741137qY/?vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">Zookeeper</a></h3></li><li><h3 id="Redis"><a href="#Redis" class="headerlink" title="Redis"></a><a href="https://www.bilibili.com/video/BV1cr4y1671t/">Redis</a></h3></li><li><h3 id="MongoDB"><a href="#MongoDB" class="headerlink" title="MongoDB"></a><a href="https://www.bilibili.com/video/BV1bJ411x7mq/">MongoDB</a></h3></li><li><h3 id="RabbitMQ"><a href="#RabbitMQ" class="headerlink" title="RabbitMQ"></a><a href="https://www.bilibili.com/video/BV1mN4y1Z7t9/">RabbitMQ</a></h3></li><li><h3 id="RocketMQ"><a href="#RocketMQ" class="headerlink" title="RocketMQ"></a><a href="https://www.bilibili.com/video/BV1L4411y7mn/">RocketMQ</a></h3></li><li><h3 id="KafKa"><a href="#KafKa" class="headerlink" title="KafKa"></a><strong>KafKa</strong></h3><p><a href="https://www.bilibili.com/video/BV1vr4y1677k/?spm_id_from=333.337.search-card.all.click%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89">https://www.bilibili.com/video/BV1vr4y1677k/?spm_id_from=333.337.search-card.all.click（尚硅谷）</a></p><p><a href="https://www.bilibili.com/video/BV19y4y1b7Uo/?spm_id_from=333.337.search-card.all.click%EF%BC%88%E9%BB%91%E9%A9%AC%EF%BC%89">https://www.bilibili.com/video/BV19y4y1b7Uo/?spm_id_from=333.337.search-card.all.click（黑马）</a></p></li><li><h3 id="activiti工作流-流程引擎"><a href="#activiti工作流-流程引擎" class="headerlink" title="activiti工作流(流程引擎)"></a>activiti工作流(流程引擎)</h3></li><li><h3 id="搜索引擎"><a href="#搜索引擎" class="headerlink" title="搜索引擎"></a><strong>搜索引擎</strong></h3><ul><li><p><strong>ElasticSeqrch（简称es）</strong></p><p><a href="https://www.bilibili.com/video/BV1nF411F75k/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1nF411F75k/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>Solr</strong></p><p><a href="https://www.bilibili.com/video/BV1dh411Q7Qu/?spm_id_from=333.337.search-card.all.click%EF%BC%88%E9%BB%91%E9%A9%AC%EF%BC%89">https://www.bilibili.com/video/BV1dh411Q7Qu/?spm_id_from=333.337.search-card.all.click（黑马）</a></p><p><a href="https://www.bilibili.com/video/BV1gZ4y1a7RH/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E5%8D%83%E5%B3%B0%EF%BC%89">https://www.bilibili.com/video/BV1gZ4y1a7RH/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（千峰）</a></p></li></ul></li><li><h3 id="Mycat"><a href="#Mycat" class="headerlink" title="Mycat"></a>Mycat</h3><ul><li><p><a href="https://www.bilibili.com/video/BV1iT41157JX/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89">https://www.bilibili.com/video/BV1iT41157JX/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（尚硅谷）</a></p></li><li><p><a href="https://www.bilibili.com/video/BV1gK4y1b7iU/?spm_id_from=333.337.search-card.all.click&vd_source=6216137a62188143a3e1e83d34f9035a2%EF%BC%88%E5%8A%A8%E5%8A%9B%E8%8A%82%E7%82%B9%EF%BC%89">https://www.bilibili.com/video/BV1gK4y1b7iU/?spm_id_from=333.337.search-card.all.click&amp;vd_source=6216137a62188143a3e1e83d34f9035a2（动力节点）</a></p></li><li><p><a href="https://www.bilibili.com/video/BV17f4y1D7pm/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E9%BB%91%E9%A9%AC%EF%BC%89">https://www.bilibili.com/video/BV17f4y1D7pm/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（黑马）</a></p></li></ul></li><li><h3 id="日志分析与监控（ELK）"><a href="#日志分析与监控（ELK）" class="headerlink" title="日志分析与监控（ELK）"></a><strong>日志分析与监控（ELK）</strong></h3><ul><li><strong>ElasticSearch（搜集，存储数据）</strong></li><li><strong>LogStatsh（分析日志）</strong></li><li><strong>Kibana（可视化）</strong></li></ul></li><li><h3 id="权限认证"><a href="#权限认证" class="headerlink" title="权限认证"></a>权限认证</h3><ul><li><p><strong><a href="https://www.bilibili.com/video/BV1VE411h7aL/?spm_id_from=333.337.search-card.all.click&vd_source=205b9aa791a13bdcc9e04b9d7d1e0544">springsecurity</a></strong></p></li><li><p><strong>Shiro</strong></p></li><li><p><strong>SaToken</strong></p></li></ul></li><li><h3 id="支付（支付宝沙箱支付，微信支付等）"><a href="#支付（支付宝沙箱支付，微信支付等）" class="headerlink" title="支付（支付宝沙箱支付，微信支付等）"></a>支付（支付宝沙箱支付，微信支付等）</h3></li></ul><h2 id="第六部分：DevOps-开发运维一体化-自动化部分管理项目，解决CI-CD"><a href="#第六部分：DevOps-开发运维一体化-自动化部分管理项目，解决CI-CD" class="headerlink" title="第六部分：DevOps(开发运维一体化)自动化部分管理项目，解决CI&#x2F;CD"></a>第六部分：DevOps(开发运维一体化)自动化部分管理项目，解决CI&#x2F;CD</h2><p><a href="https://www.bilibili.com/video/BV13Q4y1C7hS/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89">https://www.bilibili.com/video/BV13Q4y1C7hS/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（尚硅谷）</a></p><ul><li><strong>k8s</strong></li><li><strong>普罗米修斯prometheus</strong></li><li><strong>Jenkins</strong></li><li><strong>Harbor</strong></li><li><strong>GitLab</strong></li><li><strong>项目工程代码质量检测（sonarqube）</strong></li></ul><h2 id="第七部分：大数据技术"><a href="#第七部分：大数据技术" class="headerlink" title="第七部分：大数据技术"></a>第七部分：大数据技术</h2><ul><li><p><strong>Hadoop</strong></p><p><a href="https://www.bilibili.com/video/BV1Qp4y1n7EN/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1Qp4y1n7EN/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p><p><a href="https://www.bilibili.com/video/BV1CU4y1N7Sh/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1CU4y1N7Sh/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>Hive</strong></p><p><a href="https://www.bilibili.com/video/BV1EZ4y1G7iL/?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1EZ4y1G7iL/?spm_id_from=333.337.search-card.all.click</a></p><p><a href="https://www.bilibili.com/video/BV1L5411u7ae/?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1L5411u7ae/?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>Impals</strong></p><p><a href="https://www.bilibili.com/video/BV1GA411E7V9/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1GA411E7V9/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>spark</strong></p><p><a href="https://www.bilibili.com/video/BV11A411L7CK/?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV11A411L7CK/?spm_id_from=333.337.search-card.all.click</a></p><p><a href="https://www.bilibili.com/video/BV1Jq4y1z7VP/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1Jq4y1z7VP/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>flink</strong></p><p><a href="https://www.bilibili.com/video/BV133411s7Sa/?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV133411s7Sa/?spm_id_from=333.337.search-card.all.click</a></p><p><a href="https://www.bilibili.com/video/BV1Gt4y1z7bR/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1Gt4y1z7bR/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="JAVA 后端学习路线" scheme="http://example.com/categories/JAVA-%E5%90%8E%E7%AB%AF%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/"/>
    
    
  </entry>
  
  <entry>
    <title>不会再有任何的算法更新了，进度表和技术更新随缘</title>
    <link href="http://example.com/posts/3b112aa3.html"/>
    <id>http://example.com/posts/3b112aa3.html</id>
    <published>2024-04-30T13:50:22.000Z</published>
    <updated>2024-07-18T08:32:14.108Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>前后端的区别</title>
    <link href="http://example.com/posts/b3d49ee0.html"/>
    <id>http://example.com/posts/b3d49ee0.html</id>
    <published>2024-04-30T13:41:20.000Z</published>
    <updated>2024-07-18T08:33:06.739Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h3 id="1-前端开发"><a href="#1-前端开发" class="headerlink" title="1.前端开发"></a>1.前端开发</h3><h4 id="1-1-职责："><a href="#1-1-职责：" class="headerlink" title="1.1 职责："></a>1.1 职责：</h4><ul><li>负责实现用户界面，包括网页的布局、样式和交互。</li><li>与设计师合作，将设计稿转化为可交互的网页。</li><li>优化网页性能和用户体验，确保页面加载速度和响应性。</li></ul><h3 id="2-后端开发"><a href="#2-后端开发" class="headerlink" title="2.后端开发"></a>2.后端开发</h3><h4 id="2-1-职责："><a href="#2-1-职责：" class="headerlink" title="2.1 职责："></a>2.1 职责：</h4><ul><li>负责处理客户端和服务器之间的交互，处理HTTP请求和响应。</li><li>实现业务逻辑和数据处理，与数据库交互进行数据的增删改查。</li><li>确保系统的安全性和稳定性，预防数据泄露和攻击。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>前端</title>
    <link href="http://example.com/posts/f3b98ae9.html"/>
    <id>http://example.com/posts/f3b98ae9.html</id>
    <published>2024-04-30T13:34:29.000Z</published>
    <updated>2024-07-18T08:31:09.055Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h3 id="前端路线："><a href="#前端路线：" class="headerlink" title="前端路线："></a>前端路线：</h3><p>注：原创来自于晋中信息学院双体软件精英产业学院，本人二次修改并非原创</p><h4 id="第一部分：-基础"><a href="#第一部分：-基础" class="headerlink" title="第一部分：(基础)"></a>第一部分：(基础)</h4><ul><li><p><strong>html</strong></p></li><li><p><strong>css</strong></p><p><a href="https://www.bilibili.com/video/BV1XJ411X7Ud?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1XJ411X7Ud?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>html5</strong></p></li><li><p><strong>css3</strong></p><p><a href="https://www.bilibili.com/video/BV1XJ411X7Ud?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1XJ411X7Ud?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>尚优选（练习如何布局）</strong></p><p><a href="https://www.bilibili.com/video/BV1ra411X7RX/?vd_source=fb74ca8f85f5680ee6b71243e4bd4322">https://www.bilibili.com/video/BV1ra411X7RX/?vd_source=fb74ca8f85f5680ee6b71243e4bd4322</a></p></li><li><p><strong>学完这些之后，自己手敲一个京东页面，一个博学谷页面（脱离视频）</strong></p></li></ul><h4 id="第二部分：（进阶）"><a href="#第二部分：（进阶）" class="headerlink" title="第二部分：（进阶）"></a>第二部分：（进阶）</h4><ul><li><p><strong>javaScript（这个很重要）</strong></p><p><a href="https://www.bilibili.com/video/BV1YW411T7GX?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1YW411T7GX?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>javaScript高级</strong></p><p><a href="https://www.bilibili.com/video/BV14s411E7qf?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV14s411E7qf?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>AJAX（发请求用到的）</strong></p><p><a href="https://www.bilibili.com/video/BV1WC4y1b78y?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1WC4y1b78y?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>es6（同样重要）</strong></p><p><a href="https://www.bilibili.com/video/BV1uK411H7on?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1uK411H7on?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>Promise</strong></p><p><a href="https://www.bilibili.com/video/BV1GA411x7z1?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1GA411x7z1?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>axios</strong></p><p><a href="https://www.bilibili.com/video/BV1wr4y1K7tq?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1wr4y1K7tq?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>node.js（前端的后台）</strong></p><p><a href="https://www.bilibili.com/video/BV1bs411E7pD?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1bs411E7pD?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>webpack5</strong></p><p><a href="https://www.bilibili.com/video/BV1cv411C74F?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1cv411C74F?spm_id_from=333.337.search-card.all.click</a></p><p><a href="https://www.bilibili.com/video/BV1e7411j7T5/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1e7411j7T5/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p><p><a href="https://www.bilibili.com/video/BV1e7411j7T5/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1e7411j7T5/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li></ul><h4 id="第三部分：（框架）"><a href="#第三部分：（框架）" class="headerlink" title="第三部分：（框架）"></a>第三部分：（框架）</h4><ul><li><p><strong>Vue2+Vue3</strong></p><p><a href="https://www.bilibili.com/video/BV1Zy4y1K7SH?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1Zy4y1K7SH?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>vue2项目实战</strong></p><p><a href="https://www.bilibili.com/video/BV1Vf4y1T7bw/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1Vf4y1T7bw/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>微信小程序</strong></p><p><a href="https://www.bilibili.com/video/BV1834y1676P/?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1834y1676P/?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>微信小程序实战</strong></p><p><a href="https://www.bilibili.com/video/BV12K411A7A2/?spm_id_from=333.999.0.0&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV12K411A7A2/?spm_id_from=333.999.0.0&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>node项目</strong></p><p><a href="https://www.bilibili.com/video/BV17b4y1778c/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV17b4y1778c/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>vue3教学（上面大部分都为vue2，此视频为单独的vue3教学）</strong></p><p><a href="https://www.bilibili.com/video/BV1NR4y1x7Ab/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1NR4y1x7Ab/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>vue3项目实战</strong></p><p><a href="https://www.bilibili.com/video/BV1uB4y1a7se/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1uB4y1a7se/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>TypeScript</strong></p><p><a href="https://www.bilibili.com/video/BV1Xy4y1v7S2/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1Xy4y1v7S2/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>React</strong></p><p><a href="https://www.bilibili.com/video/BV1wy4y1D7JT?spm_id_from=333.337.search-card.all.click">https://www.bilibili.com/video/BV1wy4y1D7JT?spm_id_from=333.337.search-card.all.click</a></p></li><li><p><strong>React项目（react版本更新快，并且版本之间更新比较大，如果博客更新不及时，请自行选择）</strong></p><p><a href="https://www.bilibili.com/video/BV1gh411U7JD/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%882021%EF%BC%89">https://www.bilibili.com/video/BV1gh411U7JD/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（2021）</a></p><p><a href="https://www.bilibili.com/video/BV1FV4y157Zx/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2%EF%BC%882022%EF%BC%89">https://www.bilibili.com/video/BV1FV4y157Zx/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2（2022）</a></p></li></ul><h4 id="第四部分：（其他）"><a href="#第四部分：（其他）" class="headerlink" title="第四部分：（其他）"></a>第四部分：（其他）</h4><ul><li><p><strong>大厂面试题</strong></p></li><li><p><strong>Git</strong></p><p><a href="https://www.bilibili.com/video/BV1vy4y1s7k6/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1vy4y1s7k6/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p><p><a href="https://www.bilibili.com/video/BV1MU4y1Y7h5/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1MU4y1Y7h5/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li><li><p><strong>jQuery（可学可不学）</strong></p></li><li><p><strong>Linux</strong></p><p><a href="https://www.bilibili.com/video/BV1Sv411r7vd/?spm_id_from=333.337.search-card.all.click&vd_source=621637a62188143a3e1e83d34f9035a2">https://www.bilibili.com/video/BV1Sv411r7vd/?spm_id_from=333.337.search-card.all.click&amp;vd_source=621637a62188143a3e1e83d34f9035a2</a></p></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>字符串的常用api</title>
    <link href="http://example.com/posts/93fe3ac.html"/>
    <id>http://example.com/posts/93fe3ac.html</id>
    <published>2023-09-24T10:27:33.000Z</published>
    <updated>2024-07-17T16:35:13.989Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>charAt(index)：获取字符串索引为index的字符<br>substring(index1, index2)：从索引index1(包含)到索引index2(不包含)截取字符串indexOf(s)：获取字符s的索引</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">https://blog.csdn.net/weixin_40052298/article/details/121868965?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169555251216800182147809%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&amp;request_id=169555251216800182147809&amp;biz_id=0&amp;utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-2-121868965-null-null.142^v94^insert_down1&amp;utm_term=java%20substring%E6%96%B9%E6%B3%95&amp;spm=1018.2226.3001.4187</span><br></pre></td></tr></table></figure><p>contains(s)：字符串是否包含字符s<br>split(char)：按字符char对字符串进行切分</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">https://blog.csdn.net/qq_26893841/article/details/127919230?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169555212616800188571527%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&amp;request_id=169555212616800188571527&amp;biz_id=0&amp;utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-127919230-null-null.142^v94^insert_down1&amp;utm_term=javasplit&amp;spm=1018.2226.3001.4187</span><br></pre></td></tr></table></figure><p>trim()：去除字符串两端的空白字符<br>Arrays.toString(sz)：将字符数组sz转成字符串</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="竞赛算法和数据结构" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="字符串" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
    
    <category term="字符串常用api" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%AD%97%E7%AC%A6%E4%B8%B2/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E7%94%A8api/"/>
    
    
  </entry>
  
  <entry>
    <title>双指针算法</title>
    <link href="http://example.com/posts/9fba193f.html"/>
    <id>http://example.com/posts/9fba193f.html</id>
    <published>2023-09-06T07:23:27.000Z</published>
    <updated>2024-07-17T16:35:13.978Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="双指针算法"><a href="#双指针算法" class="headerlink" title="双指针算法"></a>双指针算法</h1><p>双指针算法是一种通过维护两个指针来合并两个有序序列的算法。其中，一个指针指向其中一个序列，另一个指针指向另外一个序列。在每次迭代中，两个指针分别移动一步，当两个指针都移动完毕时，整个排序过程结束。双指针算法可以优化朴素算法的时间复杂度，从O(n^2)^  优化为O(n)。优化后的算法利用了两个指针的单调性，使得我们只需要枚举O(n)个状态，而不是朴素算法中的O(n^2)个状态</p><h2 id="代码模板："><a href="#代码模板：" class="headerlink" title="代码模板："></a>代码模板：</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></pre></td><td class="code"><pre><span class="line">for(i=0,j=0;i&lt;n;i++)&#123;</span><br><span class="line"></span><br><span class="line">while(j&lt;i&amp;&amp;check(i,j) j++)</span><br><span class="line">//(check()为某个特定条件)</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></pre></td></tr></table></figure><h2 id="例题1："><a href="#例题1：" class="headerlink" title="例题1："></a>例题1：</h2><p>输入一行字母，每个单词之间有空格，把每个单词放在不同的行</p><h3 id="输入样例："><a href="#输入样例：" class="headerlink" title="输入样例："></a>输入样例：</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">abc bcd efg</span><br></pre></td></tr></table></figure><h3 id="输出样例："><a href="#输出样例：" class="headerlink" title="输出样例："></a>输出样例：</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">abc</span><br><span class="line">bcd</span><br><span class="line">efg</span><br></pre></td></tr></table></figure><h3 id="代码："><a href="#代码：" class="headerlink" title="代码："></a>代码：</h3><p><strong>java：</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></pre></td><td class="code"><pre><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        Scanner sc=new Scanner(System.in);</span><br><span class="line"></span><br><span class="line">        String s1=sc.nextLine();</span><br><span class="line"></span><br><span class="line">        int n=s1.length();</span><br><span class="line"></span><br><span class="line">        for (int i = 0; i &lt; n; i++) &#123;</span><br><span class="line"></span><br><span class="line">            int j=i;</span><br><span class="line"></span><br><span class="line">            while (j&lt;n&amp;&amp;s1.charAt(j)!=&#x27; &#x27;)  j++;</span><br><span class="line"></span><br><span class="line">            for (int k = i; k &lt; j ; k++) &#123;</span><br><span class="line">                System.out.print(s1.charAt(k));</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println();</span><br><span class="line">            i=j;</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"></span><br></pre></td></tr></table></figure><p><strong>ps！！</strong>：next()与nextLine()比较大的区别是用next()不能得到带空格的<a href="https://so.csdn.net/so/search?q=%E5%AD%97%E7%AC%A6%E4%B8%B2&spm=1001.2101.3001.7020">字符串</a>,而nextLine()可以。</p><h3 id="例题二："><a href="#例题二：" class="headerlink" title="例题二："></a>例题二：</h3><p>给定一个长度为 n 的整数序列，请找出最长的不包含重复的数的连续区间，输出它的长度。</p><h3 id="输入格式"><a href="#输入格式" class="headerlink" title="输入格式"></a>输入格式</h3><p>第一行包含整数 n。</p><p>第二行包含 n 个整数（均在 0∼10^5 范围内），表示整数序列。</p><p>输出格式</p><p>共一行，包含一个整数，表示最长的不包含重复的数的连续区间的长度。</p><h3 id="数据范围"><a href="#数据范围" class="headerlink" title="数据范围"></a>数据范围</h3><p>1≤n≤10^5</p><h3 id="输入样例：-1"><a href="#输入样例：-1" class="headerlink" title="输入样例："></a>输入样例：</h3><p>5<br>1 2 2 3 5</p><h3 id="输出样例：-1"><a href="#输出样例：-1" class="headerlink" title="输出样例："></a>输出样例：</h3><p>3</p><h3 id="代码：-1"><a href="#代码：-1" class="headerlink" title="代码："></a>代码：</h3><p>java：</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></pre></td><td class="code"><pre><span class="line">package org.example;</span><br><span class="line"></span><br><span class="line">import java.io.BufferedReader;</span><br><span class="line">import java.io.IOException;</span><br><span class="line">import java.io.InputStreamReader;</span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line"></span><br><span class="line">    final static int N=(int) (1e5+10);</span><br><span class="line"></span><br><span class="line">    static int[]arr=new int[N];</span><br><span class="line"></span><br><span class="line">    static int[]s=new int[N];</span><br><span class="line"></span><br><span class="line">//用于记录数组中数字出现的次数</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args) throws IOException &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(System.in));</span><br><span class="line"></span><br><span class="line">        int n = Integer.parseInt(bufferedReader.readLine());</span><br><span class="line"></span><br><span class="line">        String[] input = bufferedReader.readLine().split(&quot; &quot;);</span><br><span class="line"></span><br><span class="line">        for (int i = 0; i &lt; n; i++) &#123;</span><br><span class="line"></span><br><span class="line">            arr[i]=Integer.parseInt(input[i]);</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        int ans=0;</span><br><span class="line"></span><br><span class="line">//区间顺序从j到i</span><br><span class="line"></span><br><span class="line">        for (int i = 0, j=0; i &lt; n; i++) &#123;</span><br><span class="line"></span><br><span class="line">            s[arr[i]]++;</span><br><span class="line"></span><br><span class="line">            while (s[arr[i]]&gt;1&amp;&amp;i&gt;=j) &#123;</span><br><span class="line"></span><br><span class="line">                s[arr[j]]--;</span><br><span class="line"></span><br><span class="line">                j++;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">            ans=Math.max(ans, i-j+1);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(ans);</span><br><span class="line"></span><br><span class="line">        bufferedReader.close();</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;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;&#92;assets&#92;css&#92;APlayer.min.css&quot;&gt;&lt;script src=&quot;&#92;assets&#92;js&#92;APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="竞赛算法和数据结构" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="双指针算法" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%8F%8C%E6%8C%87%E9%92%88%E7%AE%97%E6%B3%95/"/>
    
    
  </entry>
  
  <entry>
    <title>前缀和与差分</title>
    <link href="http://example.com/posts/77a88a6b.html"/>
    <id>http://example.com/posts/77a88a6b.html</id>
    <published>2023-09-05T04:06:23.000Z</published>
    <updated>2024-07-17T16:35:13.970Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h1 id="前缀和与差分"><a href="#前缀和与差分" class="headerlink" title="前缀和与差分"></a>前缀和与差分</h1><h2 id="一，前缀和"><a href="#一，前缀和" class="headerlink" title="一，前缀和"></a>一，前缀和</h2><p><strong>前缀和是指某序列的前n项和，可以把它理解为数学上的数列的前n项和，而差分可以看成前缀和的逆运算。合理的使用前缀和与差分，可以将某些复杂的问题简单化。</strong></p><h3 id="1-1-一维前缀和"><a href="#1-1-一维前缀和" class="headerlink" title="1.1 一维前缀和"></a>1.1 一维前缀和</h3><h4 id="原理："><a href="#原理：" class="headerlink" title="原理："></a><strong>原理：</strong></h4><p>sum[r] &#x3D; a[1] + a[2] + a[3] + a[l-1] + a[l] + a[l + 1] …… a[r];<br>sum[l - 1] &#x3D; a[1] + a[2] + a[3] + a[l - 1];<br>sum[r] - sum[l - 1] &#x3D; a[l] + a[l + 1] + ……+ a[r];</p><h4 id="模板："><a href="#模板：" class="headerlink" title="模板："></a>模板：</h4><span id="more"></span><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line"></span><br><span class="line">        Scanner sc=new Scanner(System.in);</span><br><span class="line">        int n=sc.nextInt();</span><br><span class="line">        int[]arr=new int[n];</span><br><span class="line">        int[]sn=new int[n];</span><br><span class="line">        for (int i = 0; i &lt; arr.length; i++) &#123;</span><br><span class="line">            arr[i]=sc.nextInt();</span><br><span class="line">        &#125;</span><br><span class="line">        sn[0]=arr[0];</span><br><span class="line">        for (int i = 1; i &lt; arr.length; i++) &#123;</span><br><span class="line">            sn[i]=sn[i-1]+arr[i];</span><br><span class="line">        &#125;</span><br><span class="line">        for (int i = 0; i &lt; sn.length; i++) &#123;</span><br><span class="line">            System.out.println(sn[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        //        求l 到r 的区间和</span><br><span class="line">        int l=sc.nextInt();</span><br><span class="line">        int r=sc.nextInt();</span><br><span class="line"></span><br><span class="line">        System.out.println(sn[r]-sn[l-1]);</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="1-2二维前缀和"><a href="#1-2二维前缀和" class="headerlink" title="1.2二维前缀和"></a>1.2二维前缀和</h3><h4 id="二维前缀和预处理公式"><a href="#二维前缀和预处理公式" class="headerlink" title="二维前缀和预处理公式"></a><strong>二维前缀和预处理公式</strong></h4><p>可以看成面积（集合），</p><p><strong>s[i][j】为整个二维前缀和数组右下角的值，即可以看做整个面积</strong></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">s[i][j] = s[i - 1][j] + s[i][j - 1 ] + a[i] [j] - s[i - 1][j - 1]</span><br></pre></td></tr></table></figure><p>若求区间（例如x1,y1到x2，y2的前缀和，则为x1,y1  x2,y2所围成的面积）</p><p><strong>因此二维前缀和的结论为：</strong></p><p>以<code>(x1, y1)</code>为左上角，<code>(x2, y2)</code>为右下角的子矩阵的和为：<br><code>s[x2, y2] - s[x1 - 1, y2] - s[x2, y1 - 1] + s[x1 - 1, y1 - 1]</code></p><p>注意，构造矩阵的时候从arr【1】【1】开始，这样为了防止出现边界问题</p><h4 id="例题："><a href="#例题：" class="headerlink" title="例题："></a>例题：</h4><p>输入一个n行m列的整数矩阵，再输入q个询问，每个询问包含四个整数x1, y1, x2, y2，表示一个子矩阵的左上角坐标和右下角坐标。</p><p>对于每个询问输出子矩阵中所有数的和。</p><p><strong>输入格式</strong><br>第一行包含三个整数n，m，q。</p><p>接下来n行，每行包含m个整数，表示整数矩阵。</p><p>接下来q行，每行包含四个整数x1, y1, x2, y2，表示一组询问。</p><p><strong>输出格式</strong></p><p>共q行，每行输出一个询问的结果。</p><p><strong>数据范围</strong></p><p>1≤n,m≤1000,<br>1≤q≤200000,<br>1≤x1≤x2≤n,<br>1≤y1≤y2≤m,<br>−1000≤矩阵内元素的值≤1000</p><p><strong>输入样例：</strong></p><p>3 4 3<br>1 7 2 4<br>3 6 2 8<br>2 1 2 3<br>1 1 2 2<br>2 1 3 4<br>1 3 3 4</p><p><strong>输出样例：</strong></p><p>17<br>27<br>21</p><p><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></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">using namespace std;</span><br><span class="line"> </span><br><span class="line">const int N= 1010;</span><br><span class="line"> </span><br><span class="line">int q[N][N];</span><br><span class="line"> </span><br><span class="line">int main()&#123;</span><br><span class="line">    int n, m, qn;</span><br><span class="line">    </span><br><span class="line">    scanf(&quot;%d %d %d&quot;, &amp;n, &amp;m, &amp;qn);</span><br><span class="line">    </span><br><span class="line">    //一定要从1开始，不然边界问题好难处理</span><br><span class="line">    for(int i = 1; i &lt;= n; i++)&#123;</span><br><span class="line">        for(int j = 1; j &lt;= m; j++)&#123;</span><br><span class="line">            scanf(&quot;%d&quot;, &amp;q[i][j]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int s[N][N];</span><br><span class="line">    </span><br><span class="line">    // 构建前缀和</span><br><span class="line">    for(int i = 1; i &lt;= n; i++)&#123;</span><br><span class="line">        for(int j = 1; j &lt;= m; j++)&#123;</span><br><span class="line">            s[i][j] =s[i-1][j] + s[i][j-1]-s[i-1][j-1]+q[i][j]; </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int xa, ya, xb, yb;</span><br><span class="line">    </span><br><span class="line">    //区间更新</span><br><span class="line">    while(qn--)&#123;</span><br><span class="line">        scanf(&quot;%d %d %d %d&quot;, &amp;xa, &amp;ya, &amp;xb, &amp;yb);</span><br><span class="line">        printf(&quot;%d\n&quot;, s[xb][yb] - s[xa-1][yb] -s[xb][ya-1] +s[xa-1][ya-1]);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</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><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><br><span class="line"></span><br><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line"></span><br><span class="line">        Scanner sc=new Scanner(System.in);</span><br><span class="line"></span><br><span class="line">        int n=sc.nextInt();</span><br><span class="line">        int m=sc.nextInt();</span><br><span class="line">        int q=sc.nextInt();</span><br><span class="line"></span><br><span class="line">        int[][]arr=new int[n+1][m+1];</span><br><span class="line">        int[][]sn=new int[n+1][m+1];</span><br><span class="line"></span><br><span class="line">        for (int i = 1; i &lt;= n; i++) &#123;</span><br><span class="line">            for (int j = 1; j &lt;= m; j++) &#123;</span><br><span class="line"></span><br><span class="line">                arr[i][j]=sc.nextInt();</span><br><span class="line">                sn[i][j]=arr[i][j];</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><br><span class="line"></span><br><span class="line">        for (int i = 1; i &lt;= n; i++) &#123;</span><br><span class="line">            for (int j = 1; j &lt;= m; j++) &#123;</span><br><span class="line">                sn[i][j]+=sn[i][j-1]+sn[i-1][j]-sn[i-1][j-1];</span><br><span class="line">//      这里的+=在运算之前sn【i】【j】值为arr【i】【j】</span><br><span class="line">//sn[i][j]=arr[i][j]+sn[i][j-1]+sn[i-1][j]-sn[i-1][j-1];</span><br><span class="line">//arr[i][j]=sn[i][j]-sn[i][j-1]-sn[i-1][j]+sn[i-1][j-1]</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">while (q--&gt;=0)&#123;</span><br><span class="line">    int x1=sc.nextInt();</span><br><span class="line"></span><br><span class="line">    int y1=sc.nextInt();</span><br><span class="line"></span><br><span class="line">    int x2=sc.nextInt();</span><br><span class="line"></span><br><span class="line">    int y2=sc.nextInt();</span><br><span class="line"></span><br><span class="line">    System.out.println(sn[x2][y2]-sn[x2][y1-1]-sn[x1-1][y2]+sn[x1-1][y1-1]);</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">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="二-差分"><a href="#二-差分" class="headerlink" title="二,差分"></a>二,差分</h2><h3 id="2-1-1一维差分"><a href="#2-1-1一维差分" class="headerlink" title="2.1.1一维差分"></a>2.1.1一维差分</h3><p>类似于数学中的求导和积分，差分可以看成前缀和的逆运算。</p><p><strong>差分数组：</strong></p><p>首先给定一个原数组a：a[1], a[2], a[3],,,,,, a[n];</p><p>然后我们构造一个数组b ： b[1], b[2], b[3],,,,,, b[i];</p><p>使得 a[i] &#x3D; b[1] + b[2] + b[3] + ,,,,,, + b[i]</p><p>也就是说，a数组是b数组的前缀和数组，反过来我们把b数组叫做a数组的差分数组。换句话说，每一个a[i]都是b数组中从头开始的一段区间和。</p><p>考虑如何构造差分b数组？</p><p>最为直接的方法</p><p>如下：</p><p>a[0 ]&#x3D; 0;</p><p>b[1] &#x3D; a[1] - a[0];</p><p>b[2] &#x3D; a[2] - a[1];</p><p>b[3] &#x3D; a [3] - a[2];</p><p>……..</p><p>b[n] &#x3D; a[n] - a[n - 1];</p><h4 id="2-1-2差分数组的作用："><a href="#2-1-2差分数组的作用：" class="headerlink" title="2.1.2差分数组的作用："></a>2.1.2差分数组的作用：</h4><pre><code>    也就是在O(n)的时间， 通过 b 差分数组 可以还原出他的 前缀和数组 a ，运用 差分的思想 可以很好的解决一类问题：    例如给定一个区间 [l, r]  让a数组，这里边所有的数都加上c，如果是用遍历，那就需要O(n)的复杂度    如果用差分来做，就可以做到O(1)原理如下:  因为 ai = b1+ b2 + …+ bi    所以只需要对 b[l] 做 +c 的操作，那 a[l] 往后的数都会 +c  又因为题目要求，只是 [l, r] 的区间，所以在对b[r+1] 做-c 的操作，相抵消，那 a[r+1] 之后的数就不会加上c了，  这样再用b数组求前缀和，还原出的a数组 就是最后的结果    所以只需要O(1)的时间就可以实现，以空间换时间</code></pre><h4 id="2-1-3例题"><a href="#2-1-3例题" class="headerlink" title="2.1.3例题"></a>2.1.3例题</h4><p><strong>题目练习： AcWing 797. 差分</strong></p><p><strong>输入一个长度为n的整数序列。</strong><br>接下来输入m个操作，每个操作包含三个整数l, r, c，表示将序列中[l, r]之间的每个数加上c。<br>请你输出进行完所有操作后的序列。</p><p><strong>输入格式</strong><br>第一行包含两个整数n和m。<br>第二行包含n个整数，表示整数序列。<br>接下来m行，每行包含三个整数l，r，c，表示一个操作。</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">6 3</span><br><span class="line">1 2 2 1 2 1</span><br><span class="line">1 3 1</span><br><span class="line">3 5 1</span><br><span class="line">1 6 1</span><br></pre></td></tr></table></figure><p><strong>输出格式</strong><br>共一行，包含n个整数，表示最终序列。</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">3 4 5 3 4 2</span><br></pre></td></tr></table></figure><p>————————————————<br><strong>代码实现：</strong></p><p><strong>java:</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></pre></td><td class="code"><pre><span class="line">package org.example;</span><br><span class="line"></span><br><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line"></span><br><span class="line">        Scanner sc=new Scanner(System.in);</span><br><span class="line"></span><br><span class="line">        int n=sc.nextInt();</span><br><span class="line">        int m=sc.nextInt();</span><br><span class="line"></span><br><span class="line">        int[]arr=new int[n+100];</span><br><span class="line">        int[]b=new int[n+100];</span><br><span class="line"></span><br><span class="line">        for (int i = 1; i &lt;= n; i++) &#123;</span><br><span class="line">            arr[i]=sc.nextInt();</span><br><span class="line">//构建差分数组</span><br><span class="line">            b[i]=arr[i]-arr[i-1];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        while(m--&gt;0) &#123;</span><br><span class="line"></span><br><span class="line">            int l=sc.nextInt();</span><br><span class="line">            int r=sc.nextInt();</span><br><span class="line">            int c=sc.nextInt();</span><br><span class="line">//原数组是差分数组的前缀和数组，分别在差分数组的左右边界处分别加减c，会导致差分数组的前缀和数组除了边界值外的数保持不变</span><br><span class="line">            b[l]=b[l]+c;</span><br><span class="line">            b[r+1]=b[r+1]-c;</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">        for (int i = 1; i &lt;=n; i++) &#123;</span><br><span class="line">            arr[i]=b[i]+arr[i-1];</span><br><span class="line">            System.out.print(arr[i]+&quot;  &quot;);</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><p><strong>c++:</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></pre></td><td class="code"><pre><span class="line">#include&lt;iostream&gt;</span><br><span class="line">using namespace std;</span><br><span class="line">const int N = 1e5 + 10;</span><br><span class="line">int a[N],b[N]; </span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">    int n,m;</span><br><span class="line">    scanf(&quot;%d%d&quot;, &amp;n, &amp;m);</span><br><span class="line">    for(int i = 1;i &lt;= n; i++) </span><br><span class="line">    &#123;</span><br><span class="line">        scanf(&quot;%d&quot;, &amp;a[i]);</span><br><span class="line">        b[i] = a[i] - a[i - 1];      //构建差分数组</span><br><span class="line">    &#125;</span><br><span class="line">    int l, r, c;</span><br><span class="line">    while(m--)</span><br><span class="line">    &#123;</span><br><span class="line">        scanf(&quot;%d%d%d&quot;, &amp;l, &amp;r, &amp;c);</span><br><span class="line">        b[l] += c;     //表示将序列中[l, r]之间的每个数加上c</span><br><span class="line">        b[r + 1] -= c;</span><br><span class="line">    &#125;</span><br><span class="line">    for(int i = 1;i &lt;= n; i++) </span><br><span class="line">    &#123;</span><br><span class="line">        b[i] += b[i - 1];  //求前缀和运算</span><br><span class="line">        printf(&quot;%d &quot;,b[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="2-2-1二维差分"><a href="#2-2-1二维差分" class="headerlink" title="2.2.1二维差分"></a>2.2.1二维差分</h3><p><code>a[][]</code>数组是<code>b[][]</code>数组的前缀和数组，那么<code>b[][]</code>是<code>a[][]</code>的差分数组</p><p>原数组： <code>a[i][j]</code></p><p>我们去构造差分数组： <code>b[i][j]</code></p><p>使得<code>a</code>数组中<code>a[i][j]</code>是<code>b</code>数组左上角<code>(1,1)</code>到右下角<code>(i,j)</code>所包围矩形元素的和。</p><p>已知原数组a中被选中的子矩阵为 以(x1,y1)为左上角，以(x2,y2)为右下角所围成的矩形区域;</p><p>始终要记得，a数组是b数组的前缀和数组，比如对b数组的b[i][j]的修改，会影响到a数组中从a[i][j]及往后的每一个数。</p><p>假定我们已经构造好了b数组，类比一维差分，我们执行以下操作<br>来使被选中的子矩阵中的每个元素的值加上c</p><p>b[x1][y1】 + &#x3D; c ;</p><p>b[x1,][y2+1】- &#x3D; c;</p><p>b[x2+1][y1】- &#x3D; c;</p><p>b[x2+1][y2+1】+ &#x3D; c;</p><p>图片详解：</p><p><a href="https://img-blog.csdnimg.cn/20201217170336254.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTYyOTI4NQ==,size_16,color_FFFFFF,t_70">https://img-blog.csdnimg.cn/20201217170336254.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTYyOTI4NQ==,size_16,color_FFFFFF,t_70</a></p><p>每次对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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">for(int i = x1;i &lt;= x2;i++)</span><br><span class="line">  for(int j = y1;j &lt;= y2;j++)</span><br><span class="line">    a[i][j] += c;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="2-2-2；例题"><a href="#2-2-2；例题" class="headerlink" title="2.2.2；例题"></a>2.2.2；例题</h4><p><strong>题目练习： AcWing 798. 差分矩阵</strong><br>输入一个n行m列的整数矩阵，再输入q个操作，每个操作包含五个整数x1, y1, x2, y2, c，其中(x1, y1)和(x2, y2)表示一个子矩阵的左上角坐标和右下角坐标。<br>每个操作都要将选中的子矩阵中的每个元素的值加上c。<br>请你将进行完所有操作后的矩阵输出。<br><strong>输入格式</strong><br>第一行包含整数n, m, q。<br>接下来n行，每行包含m个整数，表示整数矩阵。<br>接下来q行，每行包含5个整数x1, y1, x2, y2, c，表示一个操作。<br><strong>输出格式</strong><br>共 n 行，每行 m 个整数，表示所有操作进行完毕后的最终矩阵。</p><p><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></pre></td><td class="code"><pre><span class="line">3 4 3</span><br><span class="line">1 2 2 1</span><br><span class="line">3 2 2 1</span><br><span class="line">1 1 1 1</span><br><span class="line">1 1 2 2 1</span><br><span class="line">1 3 2 3 2</span><br><span class="line">3 1 3 4 1</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><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></pre></td><td class="code"><pre><span class="line">2 3 4 1</span><br><span class="line">4 3 4 1</span><br><span class="line">2 2 2 2</span><br></pre></td></tr></table></figure><p><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line">import java.net.URL;</span><br><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">static final  int N= 10010;</span><br><span class="line"> static    int[][]arr=new int[N][N];</span><br><span class="line"> static    int[][]b=new int[N][N];</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line"></span><br><span class="line">        Scanner sc=new Scanner(System.in);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        int n=sc.nextInt();</span><br><span class="line">        int m=sc.nextInt();</span><br><span class="line">        int q=sc.nextInt();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        for (int i = 1; i &lt;= n; i++) &#123;</span><br><span class="line">            for (int j = 1; j &lt;=m ; j++) &#123;</span><br><span class="line">                arr[i][j]=sc.nextInt();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        for (int i = 1; i &lt;= n; i++) &#123;</span><br><span class="line">            for (int j = 1; j &lt;=m ; j++) &#123;</span><br><span class="line"></span><br><span class="line">                b[i][j]=arr[i][j]-arr[i-1][j]-arr[i][j-1]+arr[i-1][j-1];</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">        while ((q--)&gt;0)&#123;</span><br><span class="line">            int x1= sc.nextInt();</span><br><span class="line">            int y1= sc.nextInt();</span><br><span class="line">            int x2= sc.nextInt();</span><br><span class="line">            int y2= sc.nextInt();</span><br><span class="line">            int c= sc.nextInt();</span><br><span class="line"></span><br><span class="line">            insert(x1,y1,x2,y2,c);</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">        for (int i = 1; i &lt;= n; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            for (int j = 1; j &lt;= m; j++)</span><br><span class="line">            &#123;</span><br><span class="line">                arr[i][j]=b[i][j]+arr[i-1][j]+arr[i][j-1]-arr[i-1][j-1];  //二维前缀和</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        for (int i = 1; i &lt;=n ; i++) &#123;</span><br><span class="line"></span><br><span class="line">            for (int j = 1; j &lt;=m ; j++) &#123;</span><br><span class="line"></span><br><span class="line">                System.out.print(arr[i][j]+&quot;  &quot;);</span><br><span class="line"></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"></span><br><span class="line">    &#125;</span><br><span class="line">    public static void insert(int x1, int y1, int x2, int y2,int c)&#123;</span><br><span class="line">        b[x1][y1]+=c;</span><br><span class="line">        b[x1][y2+1]-=c;</span><br><span class="line">        b[x2+1][y1]-=c;</span><br><span class="line">        b[x2+1][y2+1]+=c;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;h1 id=&quot;前缀和与差分&quot;&gt;&lt;a href=&quot;#前缀和与差分&quot; class=&quot;headerlink&quot; title=&quot;前缀和与差分&quot;&gt;&lt;/a&gt;前缀和与差分&lt;/h1&gt;&lt;h2 id=&quot;一，前缀和&quot;&gt;&lt;a href=&quot;#一，前缀和&quot; class=&quot;headerlink&quot; title=&quot;一，前缀和&quot;&gt;&lt;/a&gt;一，前缀和&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;前缀和是指某序列的前n项和，可以把它理解为数学上的数列的前n项和，而差分可以看成前缀和的逆运算。合理的使用前缀和与差分，可以将某些复杂的问题简单化。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;1-1-一维前缀和&quot;&gt;&lt;a href=&quot;#1-1-一维前缀和&quot; class=&quot;headerlink&quot; title=&quot;1.1 一维前缀和&quot;&gt;&lt;/a&gt;1.1 一维前缀和&lt;/h3&gt;&lt;h4 id=&quot;原理：&quot;&gt;&lt;a href=&quot;#原理：&quot; class=&quot;headerlink&quot; title=&quot;原理：&quot;&gt;&lt;/a&gt;&lt;strong&gt;原理：&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;sum[r] &amp;#x3D; a[1] + a[2] + a[3] + a[l-1] + a[l] + a[l + 1] …… a[r];&lt;br&gt;sum[l - 1] &amp;#x3D; a[1] + a[2] + a[3] + a[l - 1];&lt;br&gt;sum[r] - sum[l - 1] &amp;#x3D; a[l] + a[l + 1] + ……+ a[r];&lt;/p&gt;
&lt;h4 id=&quot;模板：&quot;&gt;&lt;a href=&quot;#模板：&quot; class=&quot;headerlink&quot; title=&quot;模板：&quot;&gt;&lt;/a&gt;模板：&lt;/h4&gt;</summary>
    
    
    
    <category term="竞赛算法和数据结构" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="前缀和与差分" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%89%8D%E7%BC%80%E5%92%8C%E4%B8%8E%E5%B7%AE%E5%88%86/"/>
    
    
  </entry>
  
  <entry>
    <title>归并排序</title>
    <link href="http://example.com/posts/1599bffe.html"/>
    <id>http://example.com/posts/1599bffe.html</id>
    <published>2023-09-04T02:16:14.000Z</published>
    <updated>2024-07-17T16:35:13.957Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h2 id="归并排序的思想："><a href="#归并排序的思想：" class="headerlink" title="归并排序的思想："></a>归并排序的思想：</h2><p>与快排的思想很相似归并排序也是采用分治的方法，不过归并与快排的顺序是相反的，归并排序需要先划分区间，以mid &#x3D; l + r &gt;&gt; 1, 为中间点划分出两个区间对两个区间进行排序，然后再将这两个有序的区间合并成一个有序的区间。也就是说快排是从大区间一路操作到小区间，而归并是从小区间一路操作到大区间。</p><p>归并排序中最重要、最难的一步是如何合并两个有序的区间。那么这一步也是通过两个指针i,j来实现<br>当我们拥有两个区间[l, mid] ， [mid + 1, r]时，我们让两个指针同时指向两个区间的首端，即i &#x3D; l, j &#x3D; mid + 1。我们每次比较q[i] 与 q[j] 的大小，将最小的取出，取出的方法我们采用另一个数组temp[]储存，设k为存入的个数，则每次取出的操作就是temp[k++] &#x3D; q[i] ( 或q[j]) )。当其中一个指针已经走完整个区间的时候，因为两个区间都是有序的，所以可以直接将另一个区间指针后面的数插入到temp[]后面。</p><span id="more"></span><hr><h2 id="代码模板"><a href="#代码模板" class="headerlink" title="代码模板"></a>代码模板</h2><h3 id="c-："><a href="#c-：" class="headerlink" title="c++："></a>c++：</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> N=<span class="number">100010</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> q[N];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> temp[N];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</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="function"><span class="type">void</span> <span class="title">mergeSort</span><span class="params">(<span class="type">int</span> q[],<span class="type">int</span> l,<span class="type">int</span> r)</span></span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(l&gt;=r)  <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> mid=l+r&gt;&gt;<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">mergeSort</span>(q,l,mid),<span class="built_in">mergeSort</span>(q,mid<span class="number">+1</span>,r);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> k=<span class="number">0</span>,i=l,j=mid<span class="number">+1</span>;</span><br><span class="line"><span class="comment">//把一个分割好的数组分成左右俩个区间，取得中间值当分界点</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">while</span>(i&lt;=mid&amp;&amp;j&lt;=r)</span><br><span class="line"><span class="comment">// 双指针开始比较哪一个指针指向的数字更小，然后放temp数组里面</span></span><br><span class="line"><span class="keyword">if</span>(q[i]&lt;=q[j]) temp[k++]=q[i++];</span><br><span class="line"><span class="keyword">else</span>    temp[k++]=q[j++];</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span>(i&lt;=mid) temp[k++]=q[i++];</span><br><span class="line"><span class="keyword">while</span>(j&lt;=r)   temp[k++]=q[j++];</span><br><span class="line"><span class="comment">//最后把temp数组里面的数放到q数组里面 </span></span><br><span class="line"><span class="keyword">for</span>(i=l,j=<span class="number">0</span>;i&lt;=r;i++,j++) q[i]=temp[j];</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>,&amp;n) ;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;n;i++) <span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>,&amp;q[i]); </span><br><span class="line"> </span><br><span class="line"><span class="built_in">mergeSort</span>(q,<span class="number">0</span>,n<span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;n;i++) <span class="built_in">printf</span>(<span class="string">&quot;%d&quot;</span>,q[i]); </span><br><span class="line"></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><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="java："><a href="#java：" class="headerlink" title="java："></a>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></pre></td><td class="code"><pre><span class="line"> <span class="keyword">import</span> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Main</span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="type">int</span> N=<span class="number">100010</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="type">int</span>[] a=<span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">merge_sort</span><span class="params">(<span class="type">int</span>[] nums,<span class="type">int</span> l,<span class="type">int</span> r)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(l &gt;= r) <span class="keyword">return</span>;<span class="comment">//如果超出界限</span></span><br><span class="line">        <span class="type">int</span> mid=l+r&gt;&gt;<span class="number">1</span>;<span class="comment">//找到分界点</span></span><br><span class="line">        merge_sort(nums,l,mid);<span class="comment">//开始递归</span></span><br><span class="line">        merge_sort(nums,mid+<span class="number">1</span>,r);</span><br><span class="line">        <span class="type">int</span>[] temp=<span class="keyword">new</span> <span class="title class_">int</span>[r-l+<span class="number">1</span>];<span class="comment">//合并的那个数组</span></span><br><span class="line">        <span class="type">int</span> k=<span class="number">0</span>;<span class="comment">//合并数组的那个指针</span></span><br><span class="line">        <span class="type">int</span> i=l;<span class="comment">//左数组的i</span></span><br><span class="line">        <span class="type">int</span> j=mid+<span class="number">1</span>;<span class="comment">//右数组的mid+1</span></span><br><span class="line">        <span class="keyword">while</span>(i&lt;=mid&amp;&amp;j&lt;=r)&#123;</span><br><span class="line">            <span class="keyword">if</span>(nums[i]&lt;=nums[j]) temp[k++] = nums[i++];<span class="comment">//合并数组中存放的是最小的</span></span><br><span class="line">            <span class="keyword">else</span>  temp[k++] = nums[j++];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(i&lt;=mid)  temp[k++] = nums[i++];<span class="comment">//左侧小集合还有剩余，依次放入大集合尾部</span></span><br><span class="line">        <span class="keyword">while</span>(j&lt;=r)  temp[k++] = nums[j++];<span class="comment">//右侧小集合还有剩余，依次放入大集合尾部</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(i= l, j = <span class="number">0</span> ; i &lt;= r ; i++ , j++)&#123;<span class="comment">//合并操作 i 从left起</span></span><br><span class="line">            num[i] = temp[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="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> IOException&#123;</span><br><span class="line">        BufferedReader in=<span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(System.in));</span><br><span class="line">        <span class="type">int</span> n=Integer.parseInt(in.readLine());</span><br><span class="line"></span><br><span class="line">        String[]arr=in.readLine().split(<span class="string">&quot; &quot;</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;n;i++) a[i]=Integer.parseInt(arr[i]);</span><br><span class="line"></span><br><span class="line">        merge_sort(a,<span class="number">0</span>,n-<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;n;i++) System.out.print(a[i]+<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>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;归并排序的思想：&quot;&gt;&lt;a href=&quot;#归并排序的思想：&quot; class=&quot;headerlink&quot; title=&quot;归并排序的思想：&quot;&gt;&lt;/a&gt;归并排序的思想：&lt;/h2&gt;&lt;p&gt;与快排的思想很相似归并排序也是采用分治的方法，不过归并与快排的顺序是相反的，归并排序需要先划分区间，以mid &amp;#x3D; l + r &amp;gt;&amp;gt; 1, 为中间点划分出两个区间对两个区间进行排序，然后再将这两个有序的区间合并成一个有序的区间。也就是说快排是从大区间一路操作到小区间，而归并是从小区间一路操作到大区间。&lt;/p&gt;
&lt;p&gt;归并排序中最重要、最难的一步是如何合并两个有序的区间。那么这一步也是通过两个指针i,j来实现&lt;br&gt;当我们拥有两个区间[l, mid] ， [mid + 1, r]时，我们让两个指针同时指向两个区间的首端，即i &amp;#x3D; l, j &amp;#x3D; mid + 1。我们每次比较q[i] 与 q[j] 的大小，将最小的取出，取出的方法我们采用另一个数组temp[]储存，设k为存入的个数，则每次取出的操作就是temp[k++] &amp;#x3D; q[i] ( 或q[j]) )。当其中一个指针已经走完整个区间的时候，因为两个区间都是有序的，所以可以直接将另一个区间指针后面的数插入到temp[]后面。&lt;/p&gt;</summary>
    
    
    
    <category term="竞赛算法和数据结构" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="排序" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%8E%92%E5%BA%8F/"/>
    
    <category term="归并排序" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%8E%92%E5%BA%8F/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/"/>
    
    
  </entry>
  
  <entry>
    <title>快速排序</title>
    <link href="http://example.com/posts/ff8068c0.html"/>
    <id>http://example.com/posts/ff8068c0.html</id>
    <published>2023-09-03T09:27:22.000Z</published>
    <updated>2024-07-17T16:35:13.974Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h2 id="双指针思想"><a href="#双指针思想" class="headerlink" title="双指针思想"></a>双指针思想</h2><p>无需开辟额外的空间<br>有两个指针i，j，分别在最左端和最右端<br>然后i，j两个指针往中间走<br>i往中间走，直到遇到第一个大于x的数，然后停下来（因为大于x的要放在右半边）【遇到小于x的数i就继续往下走】<br>j往中间走，直到遇到第一个小于x的数，然后停下来（小于x的数放在左半边）<br>此时将i所指的数与j指的数交换一下，那么i指的新的数就是小于x的数，j指的新的数就是大于x的数，归位了。<br>接着重复这个过程，i，j往中间走；<br>直到i，j相遇，就可以把区间一分为二【左边小于x,右边大于x】<br>会发现，任何时刻i左边的数都是小于x的，j右边的数都是大于x的<br>当两个指针相遇或是穿过之后，这两个指针左边的数就是大于等于x，右边的数就是大于等于x，完美的分成两个区间</p><p>【x 归位一次，就分好一次区间，不断递归左右两个区间，直到所有的x归位】</p><span id="more"></span><hr><h2 id="快排模板"><a href="#快排模板" class="headerlink" title="快排模板"></a>快排模板</h2><h3 id="c-版本"><a href="#c-版本" class="headerlink" title="c++版本"></a>c++版本</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> N = <span class="number">1e6</span> + <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">int</span> q[N];</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">quick_sort</span><span class="params">(<span class="type">int</span> q[], <span class="type">int</span> l, <span class="type">int</span> r)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">if</span> (l &gt;= r) <span class="keyword">return</span> ; <span class="comment">// 如果数组一个数都没有或者只有一个数，就不用排序、</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//设置两个指针，以及分界点x </span></span><br><span class="line"><span class="type">int</span> x = q[l], i = l - <span class="number">1</span>, j = r + <span class="number">1</span>; <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="keyword">while</span> (i &lt; j)</span><br><span class="line">&#123;</span><br><span class="line"><span class="comment">//只有两个指针没有碰到才可以继续走</span></span><br><span class="line"><span class="keyword">do</span> ++i; <span class="keyword">while</span> (q[i] &lt; x); <span class="comment">//当 q[i] &lt; x就继续往下走</span></span><br><span class="line"><span class="keyword">do</span> --j; <span class="keyword">while</span> (q[j] &gt; x); <span class="comment">//当q[j] &gt; x就继续往下走，直到j指针指到一个&lt;=x的数，说明应该放在左边</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//判断i, j两个指针未碰到就可以交换</span></span><br><span class="line"><span class="keyword">if</span> (i &lt; j) <span class="built_in">swap</span>(q[i], q[j]); </span><br><span class="line">&#125; </span><br><span class="line"><span class="comment">//一次循环结束后，分界点x归位，接着继续分别递归左右两边</span></span><br><span class="line"><span class="built_in">quick_sort</span>(q, l, j);</span><br><span class="line"><span class="built_in">quick_sort</span>(q, j + <span class="number">1</span>, r); </span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="built_in">scanf</span> (<span class="string">&quot;%d&quot;</span>,&amp;n); <span class="comment">// 输入有几个数</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; ++i)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">scanf</span> (<span class="string">&quot;%d&quot;</span>,&amp;q[i]); <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="built_in">quick_sort</span>(q, <span class="number">0</span>, n - <span class="number">1</span>);<span class="comment">//范围0 - n-1</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; ++i) <span class="built_in">printf</span> (<span class="string">&quot;%d &quot;</span>,q[i]);</span><br><span class="line"><span class="built_in">printf</span> (<span class="string">&quot;\n&quot;</span>);</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><br></pre></td></tr></table></figure><h3 id="java版本"><a href="#java版本" class="headerlink" title="java版本"></a>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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">quickSort</span><span class="params">(<span class="type">int</span>[] arr,<span class="type">int</span> l ,<span class="type">int</span> r)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(l &gt;= r) <span class="keyword">return</span>;                  <span class="comment">//递归结束条件</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> l - <span class="number">1</span>;                      <span class="comment">//左边的指针</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> r + <span class="number">1</span>;                      <span class="comment">//右边的指针</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">x</span> <span class="operator">=</span> arr[l + ((r - l) &gt;&gt; <span class="number">1</span>)];    <span class="comment">//选取数组中间的那个数作为分界点，把数组分成两部分</span></span><br><span class="line">        <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">            <span class="keyword">do</span>&#123;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;<span class="keyword">while</span>(arr[i] &lt; x);             <span class="comment">//在左边大于分界点的数停下</span></span><br><span class="line">            <span class="keyword">do</span>&#123;</span><br><span class="line">                j--;</span><br><span class="line">            &#125;<span class="keyword">while</span>(arr[j] &gt; x);             <span class="comment">//在右边小于分界点的数停下</span></span><br><span class="line">            <span class="keyword">if</span>(i &lt; j)&#123;                      <span class="comment">//交换两个数</span></span><br><span class="line">                <span class="type">int</span> <span class="variable">temp</span> <span class="operator">=</span> arr[i];</span><br><span class="line">                arr[i] = arr[j];</span><br><span class="line">                arr[j] = temp;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        quickSort(arr,l,j);                 <span class="comment">//递归处理左边</span></span><br><span class="line">        quickSort(arr,j+<span class="number">1</span>,r);               <span class="comment">//递归处理右边</span></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;双指针思想&quot;&gt;&lt;a href=&quot;#双指针思想&quot; class=&quot;headerlink&quot; title=&quot;双指针思想&quot;&gt;&lt;/a&gt;双指针思想&lt;/h2&gt;&lt;p&gt;无需开辟额外的空间&lt;br&gt;有两个指针i，j，分别在最左端和最右端&lt;br&gt;然后i，j两个指针往中间走&lt;br&gt;i往中间走，直到遇到第一个大于x的数，然后停下来（因为大于x的要放在右半边）【遇到小于x的数i就继续往下走】&lt;br&gt;j往中间走，直到遇到第一个小于x的数，然后停下来（小于x的数放在左半边）&lt;br&gt;此时将i所指的数与j指的数交换一下，那么i指的新的数就是小于x的数，j指的新的数就是大于x的数，归位了。&lt;br&gt;接着重复这个过程，i，j往中间走；&lt;br&gt;直到i，j相遇，就可以把区间一分为二【左边小于x,右边大于x】&lt;br&gt;会发现，任何时刻i左边的数都是小于x的，j右边的数都是大于x的&lt;br&gt;当两个指针相遇或是穿过之后，这两个指针左边的数就是大于等于x，右边的数就是大于等于x，完美的分成两个区间&lt;/p&gt;
&lt;p&gt;【x 归位一次，就分好一次区间，不断递归左右两个区间，直到所有的x归位】&lt;/p&gt;</summary>
    
    
    
    <category term="竞赛算法和数据结构" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="排序" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%8E%92%E5%BA%8F/"/>
    
    <category term="快速排序" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%8E%92%E5%BA%8F/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F/"/>
    
    
  </entry>
  
  <entry>
    <title>质因子</title>
    <link href="http://example.com/posts/a8a4b497.html"/>
    <id>http://example.com/posts/a8a4b497.html</id>
    <published>2023-08-13T19:28:01.000Z</published>
    <updated>2024-07-17T16:35:13.987Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><h2 id="前缀知识"><a href="#前缀知识" class="headerlink" title="前缀知识"></a>前缀知识</h2><h3 id="算术基本定理"><a href="#算术基本定理" class="headerlink" title="算术基本定理"></a>算术基本定理</h3><p><strong>算术基本定理</strong>，又称为**<a href="https://zh.wikipedia.org/wiki/%E6%AD%A3%E6%95%B4%E6%95%B8">正整数</a>的唯一分解定理**，即：每个大于1的<a href="https://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E6%95%B0">自然数</a>，要么本身就是<a href="https://zh.wikipedia.org/wiki/%E8%B4%A8%E6%95%B0">质数</a>，要么可以写为2个或以上的质数的<a href="https://zh.wikipedia.org/wiki/%E7%A7%AF">积</a>，而且这些质因子按大小排列之后，写法仅有一种方式。</p><p><strong>例如：</strong><br>$$<br>936&#x3D;2^{3} \times 3 \times 17^{2}, 1200&#x3D;2^{4} \times 3 \times 5^{2}, 5207&#x3D;41 \times 127<br>$$</p><h2 id="质因子相关模板："><a href="#质因子相关模板：" class="headerlink" title="质因子相关模板："></a>质因子相关模板：</h2><span id="more"></span><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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><br><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">public static void main(String[] args) &#123;</span><br><span class="line">Scanner sc = new Scanner(System.in);</span><br><span class="line"></span><br><span class="line">while (sc.hasNext()) &#123;</span><br><span class="line"></span><br><span class="line">long n = sc.nextLong();</span><br><span class="line"></span><br><span class="line">int ans = 0;</span><br><span class="line">//任何一个数的质因子大于根号n的要么没有要么只有一个</span><br><span class="line">for (int i = 2; i &lt;= n / i; i++) &#123;</span><br><span class="line"></span><br><span class="line">if (n % i == 0) &#123;</span><br><span class="line">ans++;</span><br><span class="line">//设置系数</span><br><span class="line">int cnt = 0;</span><br><span class="line">while (n % i == 0) &#123;</span><br><span class="line">n /= i;</span><br><span class="line">cnt++;</span><br><span class="line">&#125;</span><br><span class="line">System.out.println(&quot;质数为&quot; + i + &quot;的幂次系数是&quot; + cnt);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">////任何一个数的质因子大于根号n的要么没有要么只有一个</span><br><span class="line">if (n &gt; 1) &#123;</span><br><span class="line">System.out.println(n + &quot;幂次系数是&quot; + 1);</span><br><span class="line">ans++;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">System.out.println(&quot;质因子种类个数为&quot; + ans);</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></pre></td></tr></table></figure><hr><h2 id="例题一："><a href="#例题一：" class="headerlink" title="例题一："></a>例题一：</h2><h3 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h3><p>给定正整数 <em>n</em>, 请问有多少个质数是 <em>n</em> 的约数。</p><h3 id="输入格式"><a href="#输入格式" class="headerlink" title="输入格式"></a>输入格式</h3><p>输入的第一行包含一个整数 <em>n</em> 。</p><h3 id="输出格式"><a href="#输出格式" class="headerlink" title="输出格式"></a>输出格式</h3><p>输出一个整数, 表示 <em>n</em> 的质数约数个数。</p><h3 id="样例输入"><a href="#样例输入" class="headerlink" title="样例输入"></a>样例输入</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">396</span><br></pre></td></tr></table></figure><h3 id="样例输出"><a href="#样例输出" class="headerlink" title="样例输出"></a>样例输出</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">3</span><br></pre></td></tr></table></figure><h3 id="样例说明"><a href="#样例说明" class="headerlink" title="样例说明"></a>样例说明</h3><p>396 有 2,3,11 三个质数约数。</p><h3 id="评测用例规模与约定"><a href="#评测用例规模与约定" class="headerlink" title="评测用例规模与约定"></a>评测用例规模与约定</h3><p>对于 30% 的评测用例, 1≤n≤10000 。</p><p>对于 60% 的评测用例, 1≤n≤10^9 。</p><p>对于所有评测用例, 1≤n≤10^16。</p><h3 id="运行限制"><a href="#运行限制" class="headerlink" title="运行限制"></a>运行限制</h3><ul><li>最大运行时间：10s</li><li>最大运行内存: 512M</li></ul><h3 id="程序代码"><a href="#程序代码" class="headerlink" title="程序代码"></a>程序代码</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></pre></td><td class="code"><pre><span class="line">package bisai;</span><br><span class="line"></span><br><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">public static void main(String[] args) &#123;</span><br><span class="line">Scanner sc = new Scanner(System.in);</span><br><span class="line"></span><br><span class="line">while (sc.hasNext()) &#123;</span><br><span class="line"></span><br><span class="line">long n = sc.nextLong();</span><br><span class="line"></span><br><span class="line">int ans = 0;</span><br><span class="line">//任何一个数的质因子大于根号n的要么没有要么只有一个</span><br><span class="line">for (int i = 2; i &lt;= n / i; i++) &#123;</span><br><span class="line"></span><br><span class="line">if (n % i == 0) &#123;</span><br><span class="line">ans++;</span><br><span class="line">//设置系数</span><br><span class="line">int cnt = 0;</span><br><span class="line">while (n % i == 0) &#123;</span><br><span class="line">n /= i;</span><br><span class="line">cnt++;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">////任何一个数的质因子大于根号n的要么没有要么只有一个</span><br><span class="line">if (n &gt; 1) &#123;</span><br><span class="line"></span><br><span class="line">ans++;</span><br><span class="line">&#125;</span><br><span class="line">System.out.println(ans);</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></pre></td></tr></table></figure><hr><h2 id="例题二"><a href="#例题二" class="headerlink" title="例题二:"></a>例题二:</h2><h3 id="问题描述-1"><a href="#问题描述-1" class="headerlink" title="问题描述"></a>问题描述</h3><p>任何一个大于 1 的正整数都能被分解为若干个质数相乘, 比如 28&#x3D;2×2×728&#x3D;2×2×7 被分解为了三个质数相乘。请问在区间 [2333333, 23333333] 中有多少个正整数 可以被分解为 12 个质数相乘?</p><h3 id="答案提交"><a href="#答案提交" class="headerlink" title="答案提交"></a>答案提交</h3><p>这是一道结果填空的题，你只需要算出结果后提交即可。本题的结果为一 个整数, 在提交答案时只填写这个整数, 填写多余的内容将无法得分。</p><h3 id="运行限制-1"><a href="#运行限制-1" class="headerlink" title="运行限制"></a>运行限制</h3><ul><li>最大运行时间：1s</li><li>最大运行内存: 512M</li></ul><h3 id="程序代码："><a href="#程序代码：" class="headerlink" title="程序代码："></a>程序代码：</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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">import java.util.Scanner;</span><br><span class="line"></span><br><span class="line">public class Main &#123;</span><br><span class="line">public static void main(String[] args) &#123;</span><br><span class="line">Scanner sc = new Scanner(System.in);</span><br><span class="line"></span><br><span class="line">while (sc.hasNext()) &#123;</span><br><span class="line"></span><br><span class="line">long n = sc.nextLong();</span><br><span class="line"></span><br><span class="line">int ans = 0;</span><br><span class="line"></span><br><span class="line">for (int j = 2333333; j &lt; 23333333; j++) &#123;</span><br><span class="line"></span><br><span class="line">int temp = j;</span><br><span class="line">int num = 0;</span><br><span class="line"></span><br><span class="line">for (int i = 2; i &lt;= temp / i; i++) &#123;</span><br><span class="line"></span><br><span class="line">while (temp % i == 0) &#123;</span><br><span class="line">temp /= i;</span><br><span class="line">num++;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">if (temp &gt; 1)</span><br><span class="line">num++;</span><br><span class="line"></span><br><span class="line">if (num == 12)</span><br><span class="line">ans++;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">System.out.println(ans);</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">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;前缀知识&quot;&gt;&lt;a href=&quot;#前缀知识&quot; class=&quot;headerlink&quot; title=&quot;前缀知识&quot;&gt;&lt;/a&gt;前缀知识&lt;/h2&gt;&lt;h3 id=&quot;算术基本定理&quot;&gt;&lt;a href=&quot;#算术基本定理&quot; class=&quot;headerlink&quot; title=&quot;算术基本定理&quot;&gt;&lt;/a&gt;算术基本定理&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;算术基本定理&lt;/strong&gt;，又称为**&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%AD%A3%E6%95%B4%E6%95%B8&quot;&gt;正整数&lt;/a&gt;的唯一分解定理**，即：每个大于1的&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E6%95%B0&quot;&gt;自然数&lt;/a&gt;，要么本身就是&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%B4%A8%E6%95%B0&quot;&gt;质数&lt;/a&gt;，要么可以写为2个或以上的质数的&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%A7%AF&quot;&gt;积&lt;/a&gt;，而且这些质因子按大小排列之后，写法仅有一种方式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;例如：&lt;/strong&gt;&lt;br&gt;$$&lt;br&gt;936&amp;#x3D;2^{3} &#92;times 3 &#92;times 17^{2}, 1200&amp;#x3D;2^{4} &#92;times 3 &#92;times 5^{2}, 5207&amp;#x3D;41 &#92;times 127&lt;br&gt;$$&lt;/p&gt;
&lt;h2 id=&quot;质因子相关模板：&quot;&gt;&lt;a href=&quot;#质因子相关模板：&quot; class=&quot;headerlink&quot; title=&quot;质因子相关模板：&quot;&gt;&lt;/a&gt;质因子相关模板：&lt;/h2&gt;</summary>
    
    
    
    <category term="竞赛算法和数据结构" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="数论" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%95%B0%E8%AE%BA/"/>
    
    <category term="质因子" scheme="http://example.com/categories/%E7%AB%9E%E8%B5%9B%E7%AE%97%E6%B3%95%E5%92%8C%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%95%B0%E8%AE%BA/%E8%B4%A8%E5%9B%A0%E5%AD%90/"/>
    
    
  </entry>
  
</feed>
