<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="https://www.w3.org/2005/Atom">
  <title>梦想启航</title>
  
  <subtitle>学习笔记、专业技术、总结回顾</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://www.180716.xyz/"/>
  <updated>2022-10-25T01:40:06.000Z</updated>
  <id>http://www.180716.xyz/</id>
  
  <author>
    <name>水郁枫子</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>MySQL8.0主从复制之Docker安装</title>
    <link href="http://www.180716.xyz/mysql/mysql/mysql8.0_docker.shtml"/>
    <id>http://www.180716.xyz/mysql/mysql/mysql8.0_docker.shtml</id>
    <published>2022-10-25T08:50:18.000Z</published>
    <updated>2022-10-25T01:40:06.000Z</updated>
    
    <content type="html"><![CDATA[<p>Docker中安装数据库，建议日常开发使用，不建议生产使用。</p><h2 id="1、Linux中安装Docker"><a href="#1、Linux中安装Docker" class="headerlink" title="1、Linux中安装Docker"></a>1、Linux中安装Docker</h2><p><strong>1、如何安装docker呢</strong></p><p>centos操作系统要采取yum install docker。。。。。</p><p>debian操作系统要采取apt install docker。。。。。</p><p>以上这种方式太麻烦，有甚者还要卸载掉以前老版本，有没有一键安装的操作方式呢，当然有的请参考：<a href="https://www.runoob.com/docker/ubuntu-docker-install.html" target="_blank" rel="noopener">https://www.runoob.com/docker/ubuntu-docker-install.html</a></p><a id="more"></a><p><strong>2、一键安装docker</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">使用官方安装脚本自动安装</span><br><span class="line">安装命令如下：</span><br><span class="line"></span><br><span class="line">curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun</span><br><span class="line">也可以使用国内 daocloud 一键安装命令：</span><br><span class="line"></span><br><span class="line">curl -sSL https://get.daocloud.io/docker | sh</span><br></pre></td></tr></table></figure><h2 id="2、安装MySQL8-0并开启主从复制"><a href="#2、安装MySQL8-0并开启主从复制" class="headerlink" title="2、安装MySQL8.0并开启主从复制"></a>2、安装MySQL8.0并开启主从复制</h2><p><strong>1、创建主服务器所需目录</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p /usr/local/mysql8.0/master/cnf</span><br><span class="line">mkdir -p /usr/local/mysql8.0/master/data</span><br></pre></td></tr></table></figure><p><strong>2、定义主服务器配置文件</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">vi /usr/local/mysql8.0/master/cnf/mysql.cnf</span><br><span class="line"></span><br><span class="line">[mysqld]</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 设置server_id,注意要唯一</span></span></span><br><span class="line">server-id=1</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 开启binlog</span></span></span><br><span class="line">log-bin=mysql-bin</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># binlog缓存</span></span></span><br><span class="line">binlog_cache_size=1M</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># binlog格式(mixed、statement、row,默认格式是statement)</span></span></span><br><span class="line">binlog_format=mixed</span><br><span class="line">character-set-server=utf8</span><br><span class="line">collation-server=utf8_general_ci</span><br><span class="line">[client]</span><br><span class="line">default-character-set=utf8</span><br><span class="line">[mysql]</span><br><span class="line">default-character-set=utf8</span><br></pre></td></tr></table></figure><p><strong>3、创建并启动mySql主服务</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd -p 3306:3306 --name master -v /usr/local/mysql8.0/master/cnf:/etc/mysql/conf.d -v /usr/local/mysql8.0/master/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0</span><br></pre></td></tr></table></figure><p><strong>4、添加复制master数据的用户reader，供从服务器使用</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[root@syfz /]# docker exec -it master /bin/bash</span><br><span class="line">root@41d795785db1:/# mysql -u root -p123456</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> create user reader@<span class="string">'%'</span> identified by <span class="string">'reader'</span>;</span></span><br><span class="line">Query OK, 0 rows affected, 1 warning (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> GRANT ALL PRIVILEGES ON *.* TO <span class="string">'reader'</span>@<span class="string">'%'</span>WITH GRANT OPTION;</span></span><br><span class="line">Query OK, 0 rows affected, 1 warning (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> FLUSH PRIVILEGES;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br></pre></td></tr></table></figure><p><strong>5、创建从服务器所需目录，编辑配置文件</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><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">mkdir /usr/local/mysql8.0/slave/cnf -p</span><br><span class="line">mkdir /usr/local/mysql8.0/slave/cnf -p</span><br><span class="line">vi /usr/local/mysql8.0/slave/cnf/mysql.cnf</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">[mysqld]</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 设置server_id,注意要唯一</span></span></span><br><span class="line">server-id=2</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 开启binlog,以备Slave作为其它Slave的Master时使用</span></span></span><br><span class="line">log-bin=mysql-slave-bin</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># relay_log配置中继日志</span></span></span><br><span class="line">relay_log=edu-mysql-relay-bin</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 如果需要同步函数或者存储过程</span></span></span><br><span class="line">log_bin_trust_function_creators=true</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># binlog缓存</span></span></span><br><span class="line">binlog_cache_size=1M</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># binlog格式(mixed、statement、row,默认格式是statement)</span></span></span><br><span class="line">binlog_format=mixed</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致</span></span></span><br><span class="line">slave_skip_errors=1062</span><br><span class="line">character-set-server=utf8</span><br><span class="line">collation-server=utf8_general_ci</span><br><span class="line">[client]</span><br><span class="line">default-character-set=utf8</span><br><span class="line">[mysql]</span><br><span class="line">default-character-set=utf8</span><br></pre></td></tr></table></figure><p><strong>6、创建并运行mysql从服务器</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd -p 3307:3306 --name slaver -v /usr/local/mysql8.0/slave/cnf:/etc/mysql/conf.d -v /usr/local/mysql8.0/slave/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0</span><br></pre></td></tr></table></figure><p><strong>7、在从服务器上配置连接主服务器的信息</strong></p><p>首先主服务器上查看master_log_file、master_log_pos两个参数，然后切换到从服务器上进行主服务器的连接信息的设置主服务上执行：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">root@6af1df686fff:/# mysql -u root -p123456</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show master status;</span></span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |</span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">| mysql-bin.000005 |      154 |              |                  |                   |</span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure><p><strong>8、docker查看主服务器容器的ip地址</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@syfz /]# docker inspect --format='&#123;&#123;.NetworkSettings.IPAddress&#125;&#125;' master</span><br><span class="line">172.17.0.2</span><br></pre></td></tr></table></figure><p><strong>9、开启主从复制配置</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line">[root@syfz /]# docker exec -it slaver /bin/bash</span><br><span class="line">root@fe8b6fc2f1ca:/# mysql -u root -p123456  </span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> change master to master_host=<span class="string">'172.17.0.2'</span>,master_user=<span class="string">'reader'</span>,master_password=<span class="string">'reader'</span>,master_log_file=<span class="string">'mysql-bin.000005'</span>,master_log_pos=154;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> start slave;</span></span><br><span class="line">Query OK, 0 rows affected, 1 warning (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show slave status\G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">               Slave_IO_State: Waiting for master to send event</span><br><span class="line">                  Master_Host: 172.17.0.2</span><br><span class="line">                  Master_User: reader</span><br><span class="line">                  Master_Port: 3306</span><br><span class="line">                Connect_Retry: 60</span><br><span class="line">              Master_Log_File: mysql-bin.000005</span><br><span class="line">          Read_Master_Log_Pos: 154</span><br><span class="line">               Relay_Log_File: edu-mysql-relay-bin.000002</span><br><span class="line">                Relay_Log_Pos: 320</span><br><span class="line">        Relay_Master_Log_File: mysql-bin.000005</span><br><span class="line">             Slave_IO_Running: Yes</span><br><span class="line">            Slave_SQL_Running: Yes</span><br><span class="line">              Replicate_Do_DB:</span><br><span class="line">          Replicate_Ignore_DB:</span><br><span class="line">           Replicate_Do_Table:</span><br><span class="line">       Replicate_Ignore_Table:</span><br><span class="line">      Replicate_Wild_Do_Table:</span><br><span class="line">  Replicate_Wild_Ignore_Table:</span><br><span class="line">                   Last_Errno: 0</span><br><span class="line">                   Last_Error:</span><br><span class="line">                 Skip_Counter: 0</span><br><span class="line">          Exec_Master_Log_Pos: 154</span><br><span class="line">              Relay_Log_Space: 531</span><br><span class="line">              Until_Condition: None</span><br><span class="line">               Until_Log_File:</span><br><span class="line">                Until_Log_Pos: 0</span><br><span class="line">           Master_SSL_Allowed: No</span><br><span class="line">           Master_SSL_CA_File:</span><br><span class="line">           Master_SSL_CA_Path:</span><br><span class="line">              Master_SSL_Cert:</span><br><span class="line">            Master_SSL_Cipher:</span><br><span class="line">               Master_SSL_Key:</span><br><span class="line">        Seconds_Behind_Master: 0</span><br><span class="line">Master_SSL_Verify_Server_Cert: No</span><br><span class="line">                Last_IO_Errno: 0</span><br><span class="line">                Last_IO_Error:</span><br><span class="line">               Last_SQL_Errno: 0</span><br><span class="line">               Last_SQL_Error:</span><br><span class="line">  Replicate_Ignore_Server_Ids:</span><br><span class="line">             Master_Server_Id: 1</span><br><span class="line">                  Master_UUID: 54a1f8d6-5056-11ed-8870-0242ac110002</span><br><span class="line">             Master_Info_File: /var/lib/mysql/master.info</span><br><span class="line">                    SQL_Delay: 0</span><br><span class="line">          SQL_Remaining_Delay: NULL</span><br><span class="line">      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates</span><br><span class="line">           Master_Retry_Count: 86400</span><br><span class="line">                  Master_Bind:</span><br><span class="line">      Last_IO_Error_Timestamp:</span><br><span class="line">     Last_SQL_Error_Timestamp:</span><br><span class="line">               Master_SSL_Crl:</span><br><span class="line">           Master_SSL_Crlpath:</span><br><span class="line">           Retrieved_Gtid_Set:</span><br><span class="line">            Executed_Gtid_Set:</span><br><span class="line">                Auto_Position: 0</span><br><span class="line">         Replicate_Rewrite_DB:</span><br><span class="line">                 Channel_Name:</span><br><span class="line">           Master_TLS_Version:</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure><p>Slave_IO_Running: Yes，Slave_SQL_Running: Yes 即表示启动成功</p><h2 id="3、测试-amp-验证"><a href="#3、测试-amp-验证" class="headerlink" title="3、测试&amp;验证"></a>3、测试&amp;验证</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="string">`user`</span> (</span><br><span class="line">  <span class="string">`id`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'id'</span>,</span><br><span class="line">  <span class="string">`name`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'用户名'</span>,</span><br><span class="line">  <span class="string">`password`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'密码'</span>,</span><br><span class="line">  <span class="string">`mobile`</span> <span class="built_in">varchar</span>(<span class="number">40</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'手机号码'</span>,</span><br><span class="line">  <span class="string">`email`</span> <span class="built_in">varchar</span>(<span class="number">100</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'邮箱'</span>,</span><br><span class="line">  <span class="string">`sex`</span> <span class="built_in">int</span>(<span class="number">1</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'性别（0：男，1：女）'</span>,</span><br><span class="line">  PRIMARY <span class="keyword">KEY</span> (<span class="string">`id`</span>)</span><br><span class="line">) <span class="keyword">ENGINE</span>=<span class="keyword">InnoDB</span> AUTO_INCREMENT=<span class="number">0</span> <span class="keyword">DEFAULT</span> <span class="keyword">CHARSET</span>=utf8 <span class="keyword">COMMENT</span>=<span class="string">'用户表'</span></span><br></pre></td></tr></table></figure><p>主从库查询下，表已经同步成功，OVER</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Docker中安装数据库，建议日常开发使用，不建议生产使用。&lt;/p&gt;
&lt;h2 id=&quot;1、Linux中安装Docker&quot;&gt;&lt;a href=&quot;#1、Linux中安装Docker&quot; class=&quot;headerlink&quot; title=&quot;1、Linux中安装Docker&quot;&gt;&lt;/a&gt;1、Linux中安装Docker&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1、如何安装docker呢&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;centos操作系统要采取yum install docker。。。。。&lt;/p&gt;
&lt;p&gt;debian操作系统要采取apt install docker。。。。。&lt;/p&gt;
&lt;p&gt;以上这种方式太麻烦，有甚者还要卸载掉以前老版本，有没有一键安装的操作方式呢，当然有的请参考：&lt;a href=&quot;https://www.runoob.com/docker/ubuntu-docker-install.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.runoob.com/docker/ubuntu-docker-install.html&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="mysql" scheme="http://www.180716.xyz/categories/mysql/"/>
    
    
  </entry>
  
  <entry>
    <title>Java修改线上JAR包</title>
    <link href="http://www.180716.xyz/java/java/java_modify_jar.shtml"/>
    <id>http://www.180716.xyz/java/java/java_modify_jar.shtml</id>
    <published>2022-02-12T10:05:41.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="方法一：简单粗暴法替换class文件"><a href="#方法一：简单粗暴法替换class文件" class="headerlink" title="方法一：简单粗暴法替换class文件"></a>方法一：简单粗暴法替换class文件</h2><p>直接下载下来jar采用本地压缩软件（7z）直接打开，讲编译好要替换的文件直接拖进去压缩即可。<br>这种方法应对class文件替换，楼主试过均可以成果启动，如果出现莫名其妙其他问题请采用方法二进行处理</p><h2 id="第二部分：采用Jar命令替换yml-、properties配置文件"><a href="#第二部分：采用Jar命令替换yml-、properties配置文件" class="headerlink" title="第二部分：采用Jar命令替换yml 、properties配置文件"></a>第二部分：采用Jar命令替换yml 、properties配置文件</h2><p>此方法亲测有效，楼主采用方法一，修改yml文件总是出现莫名其妙的问题，无法正常启动。<br>采用以下方法成功上岸，方法如下，尽情参考。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1、使用命令 jar xvf xxxx.jar</span><br><span class="line">2、解压完毕你会得到以下文件</span><br><span class="line">drwxr-xr-x 4 root root      4096 Sep 29 10:30 BOOT-INF</span><br><span class="line">drwxr-xr-x 3 root root      4096 Sep 29 10:30 META-INF</span><br><span class="line">drwxr-xr-x 3 root root      4096 Sep 29 10:30 org</span><br><span class="line">3、修改BOOT-INF下yml文件或者properties</span><br><span class="line">4、打包jar jar -uvf xxxx.jar BOOT-INF\classes\application.yml</span><br><span class="line">5、验证成果</span><br></pre></td></tr></table></figure><a id="more"></a>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;方法一：简单粗暴法替换class文件&quot;&gt;&lt;a href=&quot;#方法一：简单粗暴法替换class文件&quot; class=&quot;headerlink&quot; title=&quot;方法一：简单粗暴法替换class文件&quot;&gt;&lt;/a&gt;方法一：简单粗暴法替换class文件&lt;/h2&gt;&lt;p&gt;直接下载下来jar采用本地压缩软件（7z）直接打开，讲编译好要替换的文件直接拖进去压缩即可。&lt;br&gt;这种方法应对class文件替换，楼主试过均可以成果启动，如果出现莫名其妙其他问题请采用方法二进行处理&lt;/p&gt;
&lt;h2 id=&quot;第二部分：采用Jar命令替换yml-、properties配置文件&quot;&gt;&lt;a href=&quot;#第二部分：采用Jar命令替换yml-、properties配置文件&quot; class=&quot;headerlink&quot; title=&quot;第二部分：采用Jar命令替换yml 、properties配置文件&quot;&gt;&lt;/a&gt;第二部分：采用Jar命令替换yml 、properties配置文件&lt;/h2&gt;&lt;p&gt;此方法亲测有效，楼主采用方法一，修改yml文件总是出现莫名其妙的问题，无法正常启动。&lt;br&gt;采用以下方法成功上岸，方法如下，尽情参考。&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1、使用命令 jar xvf xxxx.jar&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2、解压完毕你会得到以下文件&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;drwxr-xr-x 4 root root      4096 Sep 29 10:30 BOOT-INF&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;drwxr-xr-x 3 root root      4096 Sep 29 10:30 META-INF&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;drwxr-xr-x 3 root root      4096 Sep 29 10:30 org&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3、修改BOOT-INF下yml文件或者properties&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4、打包jar jar -uvf xxxx.jar BOOT-INF\classes\application.yml&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5、验证成果&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://www.180716.xyz/categories/java/"/>
    
    
  </entry>
  
  <entry>
    <title>Netty中IP黑名单处理?</title>
    <link href="http://www.180716.xyz/netty/netty/black_list.shtml"/>
    <id>http://www.180716.xyz/netty/netty/black_list.shtml</id>
    <published>2021-05-07T06:36:30.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="IP黑名单介绍实战"><a href="#IP黑名单介绍实战" class="headerlink" title="IP黑名单介绍实战"></a>IP黑名单介绍实战</h2><p>根据官方文档发现RuleBasedIpFilter，进行IP过滤实现黑白名单处理。<br>官方文档地址如下：<a href="https://netty.io/4.1/api/io/netty/handler/ipfilter/IpFilterRule.html" target="_blank" rel="noopener">https://netty.io/4.1/api/io/netty/handler/ipfilter/IpFilterRule.html</a></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">IpFilterRuleHandler</span> <span class="keyword">extends</span> <span class="title">RuleBasedIpFilter</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BlackService blackService = SpringUtil.getBean(BlackService<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">accept</span><span class="params">(ChannelHandlerContext ctx, InetSocketAddress remoteAddress)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        String hostAddress = remoteAddress.getHostString();<span class="comment">//ip信息</span></span><br><span class="line">        IpFilterRuleType filterRuleType = IpFilterRuleType.ACCEPT;<span class="comment">//通过</span></span><br><span class="line">        <span class="keyword">if</span>(StrUtil.isNotBlank(hostAddress))&#123;</span><br><span class="line">            <span class="keyword">boolean</span> isReject = blackService.checkBlackList(hostAddress);<span class="comment">//检测实时黑名单</span></span><br><span class="line">            <span class="keyword">if</span>(isReject)&#123;</span><br><span class="line">                filterRuleType = IpFilterRuleType.REJECT;<span class="comment">//拒绝创建</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> filterRuleType == IpFilterRuleType.ACCEPT;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><a id="more"></a><p>当然IP过滤处理掉我们如何使用呢</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">//代码片段</span></span><br><span class="line">ServerBootstrap b = <span class="keyword">new</span> ServerBootstrap();</span><br><span class="line"> b.group(bossGroup, workerGroup).channel(NioServerSocketChannel<span class="class">.<span class="keyword">class</span>)</span></span><br><span class="line"><span class="class">         .<span class="title">childHandler</span>(<span class="title">new</span> <span class="title">ChannelInitializer</span>&lt;<span class="title">NioSocketChannel</span>&gt;() </span>&#123;</span><br><span class="line">             <span class="meta">@Override</span></span><br><span class="line">             <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(NioSocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                 <span class="comment">// 注册handler</span></span><br><span class="line">                 ch.pipeline().addLast(<span class="keyword">new</span> IpFilterRuleHandler());<span class="comment">//添加IP过滤</span></span><br><span class="line">             &#125;</span><br><span class="line">         &#125;)</span><br><span class="line">     );</span><br></pre></td></tr></table></figure><p>快来实践看结果吧</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;IP黑名单介绍实战&quot;&gt;&lt;a href=&quot;#IP黑名单介绍实战&quot; class=&quot;headerlink&quot; title=&quot;IP黑名单介绍实战&quot;&gt;&lt;/a&gt;IP黑名单介绍实战&lt;/h2&gt;&lt;p&gt;根据官方文档发现RuleBasedIpFilter，进行IP过滤实现黑白名单处理。&lt;br&gt;官方文档地址如下：&lt;a href=&quot;https://netty.io/4.1/api/io/netty/handler/ipfilter/IpFilterRule.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://netty.io/4.1/api/io/netty/handler/ipfilter/IpFilterRule.html&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight java&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;13&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;14&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;15&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;title&quot;&gt;IpFilterRuleHandler&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;title&quot;&gt;RuleBasedIpFilter&lt;/span&gt; &lt;/span&gt;&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt; BlackService blackService = SpringUtil.getBean(BlackService&lt;span class=&quot;class&quot;&gt;.&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;)&lt;/span&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;meta&quot;&gt;@Override&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;function&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;title&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;params&quot;&gt;(ChannelHandlerContext ctx, InetSocketAddress remoteAddress)&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;        String hostAddress = remoteAddress.getHostString();&lt;span class=&quot;comment&quot;&gt;//ip信息&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;        IpFilterRuleType filterRuleType = IpFilterRuleType.ACCEPT;&lt;span class=&quot;comment&quot;&gt;//通过&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;(StrUtil.isNotBlank(hostAddress))&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword&quot;&gt;boolean&lt;/span&gt; isReject = blackService.checkBlackList(hostAddress);&lt;span class=&quot;comment&quot;&gt;//检测实时黑名单&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;(isReject)&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;                filterRuleType = IpFilterRuleType.REJECT;&lt;span class=&quot;comment&quot;&gt;//拒绝创建&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;            &amp;#125;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;        &amp;#125;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; filterRuleType == IpFilterRuleType.ACCEPT;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &amp;#125;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="netty" scheme="http://www.180716.xyz/categories/netty/"/>
    
    
  </entry>
  
  <entry>
    <title>axios自定义header</title>
    <link href="http://www.180716.xyz/axios/axios/axios_header.shtml"/>
    <id>http://www.180716.xyz/axios/axios/axios_header.shtml</id>
    <published>2020-12-28T10:05:41.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：前端为什么要使用axios"><a href="#第一部分：前端为什么要使用axios" class="headerlink" title="第一部分：前端为什么要使用axios"></a>第一部分：前端为什么要使用axios</h2><p>Axios 是一个基于 promise 的 HTTP 库，可以用在浏览器和 node.js 中。<br>根据一系列搜索后，据别人吹水说axios性能会比jquery…其他请求框架要好，最重要的是它支持过滤器功能。方便前端分离项目使用。</p><figure class="highlight plain"><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"># 当然想了解更多axios请戳这里：</span><br><span class="line">http://axios-js.com/zh-cn/docs/</span><br></pre></td></tr></table></figure><h2 id="第二部分：实战与应用"><a href="#第二部分：实战与应用" class="headerlink" title="第二部分：实战与应用"></a>第二部分：实战与应用</h2><p><strong>前端JS内容</strong></p><a id="more"></a><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加一个请求拦截器</span></span><br><span class="line">axios.interceptors.request.use(<span class="function"><span class="keyword">function</span> (<span class="params">config</span>) </span>&#123;  </span><br><span class="line"> <span class="comment">// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)</span></span><br><span class="line"> <span class="comment">// 如果请求话费了超过 `timeout` 的时间，请求将被中断</span></span><br><span class="line"> config.timeout = <span class="number">20000</span>; </span><br><span class="line"> <span class="comment">// 在请求发送前做的操作</span></span><br><span class="line"> <span class="keyword">var</span> token = getToken();</span><br><span class="line"> <span class="keyword">if</span> (token) &#123;</span><br><span class="line">    config.headers[<span class="string">'TOKEN-AUTH'</span>] = token;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> config;  </span><br><span class="line">&#125;, <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line"> <span class="comment">// Do something with response error</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error);</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">axios.interceptors.response.use(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="comment">// Do something with response data</span></span><br><span class="line"> <span class="keyword">return</span> response;</span><br><span class="line">&#125;, <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line"> <span class="comment">// Do something with response error</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><strong>Nginx跨越请求配置</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">location / &#123;</span><br><span class="line">    add_header <span class="string">'Access-Control-Allow-Headers'</span> <span class="string">'其他省略,TOKEN-AUTH'</span>;</span><br><span class="line">    add_header <span class="string">'Access-Control-Allow-Methods'</span> <span class="string">'GET,POST,OPTIONS'</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#其他省略</span></span><br><span class="line">    <span class="comment">#1、说明 Access-Control-Allow-Methods 需要添加 OPTIONS,为什么需要添加OPTIONS呢？</span></span><br><span class="line">    <span class="comment">#2、说明 为什么我发起的请求有两个，一个请求类型OPTIONS，另外一个才是我正常请求呢？</span></span><br><span class="line">    <span class="comment"># 可以参考：https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS    </span></span><br><span class="line">    <span class="comment">#3、说明 Access-Control-Allow-Headers 需要添加 TOKEN-AUTH, 为了后端服务接口可以拿到前端传输的值。</span></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;第一部分：前端为什么要使用axios&quot;&gt;&lt;a href=&quot;#第一部分：前端为什么要使用axios&quot; class=&quot;headerlink&quot; title=&quot;第一部分：前端为什么要使用axios&quot;&gt;&lt;/a&gt;第一部分：前端为什么要使用axios&lt;/h2&gt;&lt;p&gt;Axios 是一个基于 promise 的 HTTP 库，可以用在浏览器和 node.js 中。&lt;br&gt;根据一系列搜索后，据别人吹水说axios性能会比jquery…其他请求框架要好，最重要的是它支持过滤器功能。方便前端分离项目使用。&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;# 当然想了解更多axios请戳这里：&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;http://axios-js.com/zh-cn/docs/&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&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;前端JS内容&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="axios" scheme="http://www.180716.xyz/categories/axios/"/>
    
    
  </entry>
  
  <entry>
    <title>SpringBoot下载大文件内存溢出处理</title>
    <link href="http://www.180716.xyz/java/java/spring_boot_download.shtml"/>
    <id>http://www.180716.xyz/java/java/spring_boot_download.shtml</id>
    <published>2020-06-10T10:05:41.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<p>文件的上传和下载是Web系统中的一个很普通的功能，实现的方式也有很多种，如利用 java.io 下面的各种IO类自己实现，或者利用 Commons IO 包中的 FileUtils 、 IOUtils 类中封装好的方法直接调用。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//此处省略N行代码</span></span><br><span class="line">ServletOutputStream os = response.getOutputStream();</span><br><span class="line">File zipFileDownLoad = <span class="comment">//此处省略下载文件代码</span></span><br><span class="line">IoUtil.write(os,<span class="keyword">true</span>,FileUtil.readBytes(zipFileDownLoad));<span class="comment">//读取文件下载</span></span><br></pre></td></tr></table></figure><p>我们大部分情况均会采用以上的方式进行处理。<br>FileUtil.readBytes 这句代码会将文件之间一次性读取到内存中。如果配置内存不能满足文件大小，结果如下👇👇👇</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java.lang.OutOfMemoryError: Java heap space <span class="comment">//这个很熟悉吧</span></span><br></pre></td></tr></table></figure><p>通常我们解决此问题方式均是</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m -XX:MaxPermSize=256m</span><br></pre></td></tr></table></figure><p>但即使按照把上面的参数配置都扩大一倍，在下载更大的文件时还是会遇到 java.lang.OutOfMemoryError: Java heap space 这个错误，上面的解决方法治标不治本。分析下异常堆栈可以发现问题产生的根源在于 FileUtil.readBytes这行代码，FileUtil.readBytes 会把文件一次性读入内存中，要下载的文件越大，需要占用的内存也越大，当文件的大小超过JVM和Tomcat的内存配置时，OutOfMemoryError 这个问题就会不可避免的发生。</p><a id="more"></a><p>搞清楚问题根源之后，那么我们如何处理此类问题。利用普通的文件输出流按字节分段写入文件，把占用的内存固定在一个指定的范围内，从根本上避免内存占用过高的问题。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">InputStream is = <span class="keyword">new</span> FileInputStream(fileDownLoad);<span class="comment">//需要下载文件，读取固定的字节数，写入os中</span></span><br><span class="line"><span class="keyword">int</span> read;</span><br><span class="line"><span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">2048</span>];</span><br><span class="line"><span class="keyword">while</span>((read = is.read(bytes))!=-<span class="number">1</span>)&#123;<span class="comment">//按字节逐个写入，避免内存占用过高</span></span><br><span class="line">os.write(bytes, <span class="number">0</span>, read);</span><br><span class="line">&#125;</span><br><span class="line">os.flush();</span><br><span class="line">is.close();<span class="comment">//记得关闭流</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;文件的上传和下载是Web系统中的一个很普通的功能，实现的方式也有很多种，如利用 java.io 下面的各种IO类自己实现，或者利用 Commons IO 包中的 FileUtils 、 IOUtils 类中封装好的方法直接调用。&lt;/p&gt;
&lt;figure class=&quot;highlight java&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;//此处省略N行代码&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;ServletOutputStream os = response.getOutputStream();&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;File zipFileDownLoad = &lt;span class=&quot;comment&quot;&gt;//此处省略下载文件代码&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;IoUtil.write(os,&lt;span class=&quot;keyword&quot;&gt;true&lt;/span&gt;,FileUtil.readBytes(zipFileDownLoad));&lt;span class=&quot;comment&quot;&gt;//读取文件下载&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;我们大部分情况均会采用以上的方式进行处理。&lt;br&gt;FileUtil.readBytes 这句代码会将文件之间一次性读取到内存中。如果配置内存不能满足文件大小，结果如下👇👇👇&lt;/p&gt;
&lt;figure class=&quot;highlight java&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;java.lang.OutOfMemoryError: Java heap space &lt;span class=&quot;comment&quot;&gt;//这个很熟悉吧&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;通常我们解决此问题方式均是&lt;/p&gt;
&lt;figure class=&quot;highlight shell&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m -XX:MaxPermSize=256m&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;但即使按照把上面的参数配置都扩大一倍，在下载更大的文件时还是会遇到 java.lang.OutOfMemoryError: Java heap space 这个错误，上面的解决方法治标不治本。分析下异常堆栈可以发现问题产生的根源在于 FileUtil.readBytes这行代码，FileUtil.readBytes 会把文件一次性读入内存中，要下载的文件越大，需要占用的内存也越大，当文件的大小超过JVM和Tomcat的内存配置时，OutOfMemoryError 这个问题就会不可避免的发生。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://www.180716.xyz/categories/java/"/>
    
    
  </entry>
  
  <entry>
    <title>Redisson之RRateLimiterHTTP限流</title>
    <link href="http://www.180716.xyz/java/redisson/redisson_http_limiter.shtml"/>
    <id>http://www.180716.xyz/java/redisson/redisson_http_limiter.shtml</id>
    <published>2020-04-27T12:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<p>基于Redis的分布式限流器（RateLimiter）可以用来在分布式环境下现在请求方的调用频率。既适用于不同Redisson实例下的多线程限流，也适用于相同Redisson实例下的多线程限流。该算法不保证公平性。除了同步接口外，还提供了异步（Async）、反射式（Reactive）和RxJava2标准的接口。</p><h2 id="如何限制HTTP请求次数（分布式）"><a href="#如何限制HTTP请求次数（分布式）" class="headerlink" title="如何限制HTTP请求次数（分布式）"></a>如何限制HTTP请求次数（分布式）</h2><p>本地缓存显然不能满足，只能考虑redis当然redis中采用lua脚本也是可以实现的。今天文中的redisson中RateLimiter也是可以的</p><p>官方例子看一下 <a href="https://github.com/redisson/redisson/wiki/6.-%E5%88%86%E5%B8%83%E5%BC%8F%E5%AF%B9%E8%B1%A1" target="_blank" rel="noopener">https://github.com/redisson/redisson/wiki/6.-%E5%88%86%E5%B8%83%E5%BC%8F%E5%AF%B9%E8%B1%A1</a></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">RRateLimiter rateLimiter = redisson.getRateLimiter(<span class="string">"myRateLimiter"</span>);</span><br><span class="line"><span class="comment">// 初始化</span></span><br><span class="line"><span class="comment">// 最大流速 = 每1秒钟产生10个令牌</span></span><br><span class="line">rateLimiter.trySetRate(RateType.OVERALL, <span class="number">10</span>, <span class="number">1</span>, RateIntervalUnit.SECONDS);</span><br><span class="line"></span><br><span class="line">CountDownLatch latch = <span class="keyword">new</span> CountDownLatch(<span class="number">2</span>);</span><br><span class="line">limiter.acquire(<span class="number">3</span>);</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">Thread t = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">    limiter.acquire(<span class="number">2</span>);</span><br><span class="line">    <span class="comment">// ...        </span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><a id="more"></a><p><strong>1、创建AOP切面</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Scope</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RateLimitAop</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> RedissonClient redissonClient;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Pointcut</span>(<span class="string">"@annotation(com.data.estimated.limiter.RateLimitAspect)"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serviceLimit</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Around</span>(<span class="string">"serviceLimit()"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">around</span><span class="params">(ProceedingJoinPoint joinPoint)</span> </span>&#123;</span><br><span class="line">        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());</span><br><span class="line">        HttpServletRequest request = servletRequestAttributes.getRequest();<span class="comment">//获取请求</span></span><br><span class="line">        HttpServletResponse response = servletRequestAttributes.getResponse();<span class="comment">//获取响应</span></span><br><span class="line">        StringBuffer buffer = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">        String url = request.getRequestURI();</span><br><span class="line">        buffer.append(StrUtil.replace(url,<span class="string">"/"</span>,<span class="string">"_"</span>));</span><br><span class="line">        buffer.append(<span class="string">"_"</span>);</span><br><span class="line">        buffer.append(IPUtil.getIpAddr(request));<span class="comment">//获取请求IP信息</span></span><br><span class="line">        RRateLimiter rRateLimiter = getRRateLimiter(joinPoint,buffer.toString());<span class="comment">//获取配置RRateLimiter信息</span></span><br><span class="line">        <span class="keyword">boolean</span> flag = rRateLimiter.tryAcquire();</span><br><span class="line">        Object obj = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (flag) &#123;</span><br><span class="line">                obj = joinPoint.proceed();</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                outRateLimiterMsg(response,<span class="keyword">new</span> JSONObject(BaseResult.LIMIT_FAIL()).toString());<span class="comment">//响应浏览器,超频请求</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            outRateLimiterMsg(response,<span class="keyword">new</span> JSONObject(BaseResult.FAIL()).toString());<span class="comment">//响应浏览器,错误</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> joinPoint</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> limitKey</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> RRateLimiter <span class="title">getRRateLimiter</span><span class="params">(ProceedingJoinPoint joinPoint,String limitKey)</span></span>&#123;</span><br><span class="line">        RateLimitAspect rateLimit = getRateLimitAspect(joinPoint);</span><br><span class="line">        <span class="keyword">long</span> count = rateLimit.count();<span class="comment">//限流次数</span></span><br><span class="line">        <span class="keyword">long</span> time = rateLimit.time();<span class="comment">//限流时间</span></span><br><span class="line">        RRateLimiter rRateLimiter = redissonClient.getRateLimiter(StrUtil.isBlank(rateLimit.key()) ? limitKey : rateLimit.key());</span><br><span class="line">        <span class="keyword">if</span>(rRateLimiter.isExists())&#123;</span><br><span class="line">            RateLimiterConfig rateLimiterConfig = rRateLimiter.getConfig();<span class="comment">//读取已经存在配置</span></span><br><span class="line">            <span class="keyword">long</span> rateInterval = rateLimiterConfig.getRateInterval();<span class="comment">//限时时间</span></span><br><span class="line">            <span class="keyword">long</span> rate = rateLimiterConfig.getRate();<span class="comment">//次数</span></span><br><span class="line">            <span class="keyword">if</span>(time != rateInterval || rate != count)&#123;</span><br><span class="line">                rRateLimiter.delete();<span class="comment">//移除配置，重新加载配置</span></span><br><span class="line">                rRateLimiter.trySetRate(RateType.OVERALL, count ,time , RateIntervalUnit.SECONDS);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        rRateLimiter.trySetRate(RateType.OVERALL, count ,time , RateIntervalUnit.SECONDS);</span><br><span class="line">        <span class="keyword">return</span> rRateLimiter;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取脚注配置信息</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> joinPoint</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> RateLimitAspect <span class="title">getRateLimitAspect</span><span class="params">(ProceedingJoinPoint joinPoint)</span></span>&#123;</span><br><span class="line">        MethodSignature signature = (MethodSignature) joinPoint.getSignature();</span><br><span class="line">        Method method = signature.getMethod();</span><br><span class="line">        RateLimitAspect rateLimit = method.getAnnotation(RateLimitAspect<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">        <span class="keyword">return</span> rateLimit;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 客户端返回数据</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">outRateLimiterMsg</span><span class="params">(HttpServletResponse response,String message)</span></span>&#123;</span><br><span class="line">        PrintWriter writer = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            response.reset();</span><br><span class="line">            response.setCharacterEncoding(<span class="string">"utf-8"</span>);</span><br><span class="line">            response.setHeader(<span class="string">"content-type"</span>, <span class="string">"application/json;charset=utf-8"</span>);</span><br><span class="line">            response.addHeader(<span class="string">"Access-Control-Allow-Origin"</span>, <span class="string">"*"</span>);</span><br><span class="line">            response.addHeader(<span class="string">"Access-Control-Allow-Headers"</span>, <span class="string">"X-Requested-With"</span>);</span><br><span class="line">            response.addHeader(<span class="string">"Access-Control-Allow-Methods"</span>, <span class="string">"GET,POST,OPTIONS"</span>);</span><br><span class="line">            writer = response.getWriter();</span><br><span class="line">            writer.write(message);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            IoUtil.close(writer);</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>2、创建脚注</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自定义注解可以不包含属性，成为一个标识注解</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Target</span>(&#123;ElementType.METHOD, ElementType.FIELD, ElementType.TYPE&#125;)</span><br><span class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> RateLimitAspect &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 限流唯一标示</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">String <span class="title">key</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 限流时间</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">long</span> <span class="title">time</span><span class="params">()</span> <span class="keyword">default</span> 5</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 限流次数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">long</span> <span class="title">count</span><span class="params">()</span> <span class="keyword">default</span> 1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>最后一步实战操作</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//默认无参数方法</span></span><br><span class="line"><span class="meta">@RateLimitAspect</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//有参数</span></span><br><span class="line"><span class="meta">@RateLimitAspect</span>(key = <span class="string">"RateLimitAspect"</span>,count = <span class="number">2</span>,time = <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//如果可以多个方法key均为RateLimitAspect这采用同一个限制。</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;基于Redis的分布式限流器（RateLimiter）可以用来在分布式环境下现在请求方的调用频率。既适用于不同Redisson实例下的多线程限流，也适用于相同Redisson实例下的多线程限流。该算法不保证公平性。除了同步接口外，还提供了异步（Async）、反射式（Reactive）和RxJava2标准的接口。&lt;/p&gt;
&lt;h2 id=&quot;如何限制HTTP请求次数（分布式）&quot;&gt;&lt;a href=&quot;#如何限制HTTP请求次数（分布式）&quot; class=&quot;headerlink&quot; title=&quot;如何限制HTTP请求次数（分布式）&quot;&gt;&lt;/a&gt;如何限制HTTP请求次数（分布式）&lt;/h2&gt;&lt;p&gt;本地缓存显然不能满足，只能考虑redis当然redis中采用lua脚本也是可以实现的。今天文中的redisson中RateLimiter也是可以的&lt;/p&gt;
&lt;p&gt;官方例子看一下 &lt;a href=&quot;https://github.com/redisson/redisson/wiki/6.-%E5%88%86%E5%B8%83%E5%BC%8F%E5%AF%B9%E8%B1%A1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/redisson/redisson/wiki/6.-%E5%88%86%E5%B8%83%E5%BC%8F%E5%AF%B9%E8%B1%A1&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight java&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;13&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;RRateLimiter rateLimiter = redisson.getRateLimiter(&lt;span class=&quot;string&quot;&gt;&quot;myRateLimiter&quot;&lt;/span&gt;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// 初始化&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// 最大流速 = 每1秒钟产生10个令牌&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;rateLimiter.trySetRate(RateType.OVERALL, &lt;span class=&quot;number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;, RateIntervalUnit.SECONDS);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;CountDownLatch latch = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; CountDownLatch(&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;limiter.acquire(&lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;Thread t = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Thread(() -&amp;gt; &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    limiter.acquire(&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// ...        &lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;);&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://www.180716.xyz/categories/java/"/>
    
    
  </entry>
  
  <entry>
    <title>Redisson学习笔记</title>
    <link href="http://www.180716.xyz/redis/redisson/redisson.shtml"/>
    <id>http://www.180716.xyz/redis/redisson/redisson.shtml</id>
    <published>2020-03-31T15:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<p>Redisson底层采用的是Netty 框架。支持Redis 2.8以上版本，支持Java1.6+以上版本。<br>Redisson是一个在Redis的基础上实现的Java驻内存数据网格（In-Memory Data Grid）。它不仅提供了一系列的分布式的Java常用对象，还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离（Separation of Concern），从而让使用者能够将精力更集中地放在处理业务逻辑上。</p><h2 id="SpringBoot集成Redisson"><a href="#SpringBoot集成Redisson" class="headerlink" title="SpringBoot集成Redisson"></a>SpringBoot集成Redisson</h2><p><strong>1、pom中maven配置</strong></p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.redisson<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>redisson-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">version</span>&gt;</span>3.12.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>2、yml配置集成Redisson</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><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">spring: #redisson 配置信息  </span><br><span class="line"> redis:</span><br><span class="line">  redisson:</span><br><span class="line">   config: classpath:config/SingleServerConfig.yml</span><br></pre></td></tr></table></figure><a id="more"></a><p>config/SingleServerConfig.yml配置如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">singleServerConfig:</span><br><span class="line">  idleConnectionTimeout: 10000</span><br><span class="line">  pingTimeout: 1000</span><br><span class="line">  connectTimeout: 10000</span><br><span class="line">  timeout: 3000</span><br><span class="line">  retryAttempts: 3</span><br><span class="line">  retryInterval: 1500</span><br><span class="line">  reconnectionTimeout: 3000</span><br><span class="line">  failedAttempts: 3</span><br><span class="line">  password: passwd</span><br><span class="line">  subscriptionsPerConnection: 5</span><br><span class="line">  clientName: &quot;redisGo&quot;</span><br><span class="line">  address: &quot;redis://domian.com:6379&quot;</span><br><span class="line">  subscriptionConnectionMinimumIdleSize: 1</span><br><span class="line">  subscriptionConnectionPoolSize: 50</span><br><span class="line">  connectionMinimumIdleSize: 32</span><br><span class="line">  connectionPoolSize: 64</span><br><span class="line">  database: 0</span><br><span class="line">  dnsMonitoringInterval: 5000</span><br><span class="line">threads: 0</span><br><span class="line">nettyThreads: 0</span><br><span class="line">codec: !&lt;org.redisson.codec.JsonJacksonCodec&gt; &#123;&#125;</span><br><span class="line">transportMode: &quot;NIO&quot;</span><br></pre></td></tr></table></figure><p>请参考:<a href="https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95" target="_blank" rel="noopener">https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95</a></p><p><strong>3、redisson订阅实战</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//第一步引入</span></span><br><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> RedissonClient redissonClient;</span><br><span class="line"></span><br><span class="line"><span class="comment">//第二部消息发布</span></span><br><span class="line">RTopic rTopic = redissonClient.getTopic(<span class="string">"RTopicTest"</span>, <span class="keyword">new</span> SerializationCodec());</span><br><span class="line">JSONObject msg = <span class="keyword">new</span> JSONObject();</span><br><span class="line">msg.put(<span class="string">"msg"</span>,<span class="string">"订阅测试"</span>);</span><br><span class="line">rTopic.publish(msg);</span><br><span class="line"></span><br><span class="line"><span class="comment">//第三部消息订阅</span></span><br><span class="line"> RTopic rTopic = redissonClient.getTopic(<span class="string">"RTopicTest"</span>,<span class="keyword">new</span> SerializationCodec());</span><br><span class="line">    rTopic.addListener(JSONObject<span class="class">.<span class="keyword">class</span>,<span class="title">new</span> <span class="title">MessageListener</span>&lt;<span class="title">JSONObject</span>&gt;()</span>&#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onMessage</span><span class="params">(CharSequence charSequence, JSONObject msg)</span> </span>&#123;</span><br><span class="line">            System.out.println(<span class="string">"MSG:"</span>msg.get(<span class="string">"msg"</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure><p><strong>4、redisson之分布式锁：</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">redissonClient.getBucket(<span class="string">"MY_LOCK_VALUES"</span>).set(<span class="string">"1111111"</span>);</span><br><span class="line">RLock lock = redissonClient.getLock(<span class="string">"myLock"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// traditional lock method</span></span><br><span class="line"><span class="comment">//lock.lock();</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// or acquire lock and automatically unlock it after 10 seconds</span></span><br><span class="line"><span class="comment">//lock.lock(10, TimeUnit.SECONDS);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// or wait for lock aquisition up to 100 seconds</span></span><br><span class="line"><span class="comment">// and automatically unlock it after 10 seconds</span></span><br><span class="line"><span class="keyword">boolean</span> res = lock.tryLock(<span class="number">100</span>, <span class="number">10</span>, TimeUnit.SECONDS);</span><br><span class="line">String result = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">if</span> (res) &#123;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    result = redissonClient.getBucket(<span class="string">"MY_LOCK_VALUES"</span>).get().toString();</span><br><span class="line">&#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">    lock.unlock();</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Redisson底层采用的是Netty 框架。支持Redis 2.8以上版本，支持Java1.6+以上版本。&lt;br&gt;Redisson是一个在Redis的基础上实现的Java驻内存数据网格（In-Memory Data Grid）。它不仅提供了一系列的分布式的Java常用对象，还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离（Separation of Concern），从而让使用者能够将精力更集中地放在处理业务逻辑上。&lt;/p&gt;
&lt;h2 id=&quot;SpringBoot集成Redisson&quot;&gt;&lt;a href=&quot;#SpringBoot集成Redisson&quot; class=&quot;headerlink&quot; title=&quot;SpringBoot集成Redisson&quot;&gt;&lt;/a&gt;SpringBoot集成Redisson&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1、pom中maven配置&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight xml&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.redisson&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;redisson-spring-boot-starter&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.12.3&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;2、yml配置集成Redisson&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;spring: #redisson 配置信息  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt; redis:&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  redisson:&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;   config: classpath:config/SingleServerConfig.yml&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="redis" scheme="http://www.180716.xyz/categories/redis/"/>
    
    
  </entry>
  
  <entry>
    <title>MySQL之federated数据表映射</title>
    <link href="http://www.180716.xyz/mysql/mysql/mysql_learn.shtml"/>
    <id>http://www.180716.xyz/mysql/mysql/mysql_learn.shtml</id>
    <published>2020-02-28T08:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<p>FEDERATED是什么呢？<br>通过FEDERATED引擎创建的表只是在本地有表定义文件，数据文件则存在于远程数据库中。就是说，这种建表方式只会在数据库A中创建一个表B的表结构文件，表的索引、数据等文件还是在机器B上的数据库B中，相当于只是在数据库A中创建了表B的一个快捷方式。</p><h2 id="1、：如何开启"><a href="#1、：如何开启" class="headerlink" title="1、：如何开启"></a>1、：如何开启</h2><p><strong>1、是否支持FEDERATED引擎</strong></p><p><img src="/upload/mysql/federated_engines_support.png" alt="alt text" title="是否支持FEDERATED引擎"></p><a id="more"></a><p><strong>2、开启FEDERATED引擎</strong><br>window 修改my.ini文件/ linux 修改my.cof文件, 在[mysqld]节点下添加federated。</p><p><img src="/upload/mysql/federated_engines.png" alt="alt text" title="开启FEDERATED引擎"></p><p>你的MYSQL已经支持FEDERATED引擎了</p><h2 id="2、如何使用"><a href="#2、如何使用" class="headerlink" title="2、如何使用"></a>2、如何使用</h2><p>举个栗子，A服务器 127.0.0.1 数据库 test 表 user （本地数据）<br>         B服务器 192.168.1.100 数据库 dev 表user （远程数据）<br>         需要将B服务器 dev库 user表数据映射到本地 test库 user表中</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#远程dev数据库user表结构</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="string">`user`</span> (</span><br><span class="line">  <span class="string">`id`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'id'</span>,</span><br><span class="line">  <span class="string">`name`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'用户名'</span>,</span><br><span class="line">  <span class="string">`password`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'密码'</span>,</span><br><span class="line">  <span class="string">`mobile`</span> <span class="built_in">varchar</span>(<span class="number">40</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'手机号码'</span>,</span><br><span class="line">  <span class="string">`email`</span> <span class="built_in">varchar</span>(<span class="number">100</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'邮箱'</span>,</span><br><span class="line">  <span class="string">`sex`</span> <span class="built_in">int</span>(<span class="number">1</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'性别（0：男，1：女）'</span>,</span><br><span class="line">  PRIMARY <span class="keyword">KEY</span> (<span class="string">`id`</span>)</span><br><span class="line">) <span class="keyword">ENGINE</span>=<span class="keyword">InnoDB</span> AUTO_INCREMENT=<span class="number">0</span> <span class="keyword">DEFAULT</span> <span class="keyword">CHARSET</span>=utf8 <span class="keyword">COMMENT</span>=<span class="string">'用户表'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 在本地test数据库中创建执行</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="string">`user`</span> (</span><br><span class="line">  <span class="string">`id`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'id'</span>,</span><br><span class="line">  <span class="string">`name`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'用户名'</span>,</span><br><span class="line">  <span class="string">`password`</span> <span class="built_in">varchar</span>(<span class="number">255</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'密码'</span>,</span><br><span class="line">  <span class="string">`mobile`</span> <span class="built_in">varchar</span>(<span class="number">40</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'手机号码'</span>,</span><br><span class="line">  <span class="string">`email`</span> <span class="built_in">varchar</span>(<span class="number">100</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'邮箱'</span>,</span><br><span class="line">  <span class="string">`sex`</span> <span class="built_in">int</span>(<span class="number">1</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'性别（0：男，1：女）'</span>,</span><br><span class="line">  PRIMARY <span class="keyword">KEY</span> (<span class="string">`id`</span>)</span><br><span class="line">) <span class="keyword">ENGINE</span>=<span class="keyword">InnoDB</span> AUTO_INCREMENT=<span class="number">0</span> <span class="keyword">DEFAULT</span> <span class="keyword">CHARSET</span>=utf8 <span class="keyword">COMMENT</span>=<span class="string">'用户表'</span></span><br><span class="line"><span class="keyword">ENGINE</span> =FEDERATED <span class="keyword">CONNECTION</span>=<span class="string">'mysql://root:passwd@192.168.1.100:3306/dev/user'</span>;</span><br></pre></td></tr></table></figure><p>执行完成后、就可以尽情测试了</p><h2 id="3、注意"><a href="#3、注意" class="headerlink" title="3、注意"></a>3、注意</h2><p>1、FEDERATED 表不支持通常意义的索引,服务器从远程库获取所有的行然后在本地进行过滤,不管是否加了where条件或limit限制。<br>　　–查询可能造成性能下降和网络负载,因为查询返回的数据必须存放在内存中,所以容易造成使用系统的swap分区或挂起。<br>2、目标端建表结构可以与源端不一样 推荐与源端结构一致<br>3、源端DDL语句更改表结构 目标端不会变化<br>4、源端DML语句目标端查询会同步<br>5、源端drop表 目标端结构还在但无法查询<br>6、目标端不能执行DDL语句<br>7、目标端执行DML语句 源端数据也会变化<br>8、目标端truncate表 源端表数据也会被清空<br>9、目标端drop表对源端无影响</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;FEDERATED是什么呢？&lt;br&gt;通过FEDERATED引擎创建的表只是在本地有表定义文件，数据文件则存在于远程数据库中。就是说，这种建表方式只会在数据库A中创建一个表B的表结构文件，表的索引、数据等文件还是在机器B上的数据库B中，相当于只是在数据库A中创建了表B的一个快捷方式。&lt;/p&gt;
&lt;h2 id=&quot;1、：如何开启&quot;&gt;&lt;a href=&quot;#1、：如何开启&quot; class=&quot;headerlink&quot; title=&quot;1、：如何开启&quot;&gt;&lt;/a&gt;1、：如何开启&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1、是否支持FEDERATED引擎&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/upload/mysql/federated_engines_support.png&quot; alt=&quot;alt text&quot; title=&quot;是否支持FEDERATED引擎&quot;&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="mysql" scheme="http://www.180716.xyz/categories/mysql/"/>
    
    
  </entry>
  
  <entry>
    <title>Nginx学习笔记</title>
    <link href="http://www.180716.xyz/nginx/nginx/nginx_learn.shtml"/>
    <id>http://www.180716.xyz/nginx/nginx/nginx_learn.shtml</id>
    <published>2020-01-08T11:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：Nginx学习必知"><a href="#第一部分：Nginx学习必知" class="headerlink" title="第一部分：Nginx学习必知"></a>第一部分：Nginx学习必知</h2><p>Nginx是一个以高性能、高并发著称的HTTP服务器，它支持HTTP（HyperText Transfer Protocol，超文本传输协议）反向代理、TCP（Transmission Control Protocol，传输控制协议）代理、负载均衡、HTTP缓存及Web开发等。</p><p><strong>HTTP请求报文</strong><br>1、请求行，包括请求方法、请求URL（Uniform Resource Locator，统一资源定位符）、HTTP及其版本号。</p><ul><li>HTTP1.1  （PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH）兼容HTTP1.0</li><li>HTTP1.0  （GET、HEAD、POST）等</li></ul><p>2、请求头、指客户端向服务器传输请求时附加的一些信息，有key/value组成，使用:隔开。常见key（Cookie、User_Agent、Accept-Encoding）等。<br>3、请求体、一般由POST请求方法进行提交，可以传输图片、文件或者字符串等。</p><p><strong>HTTP相应报文</strong><br>1、响应行、包含HTTP版本号、状态码、状态码描述。</p><a id="more"></a><table><thead><tr><th align="left">响应码</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">1XX</td><td align="left">表示已经被接受，正在继续处理。这种响应时临时响应，不会返回响应体。</td></tr><tr><td align="left">2XX</td><td align="left">表示请求被服务器接受并已经完成出来过程。</td></tr><tr><td align="left">3XX</td><td align="left">重定向，告知客户端需要继续执行操作才可以完成请求。</td></tr><tr><td align="left">4XX</td><td align="left">出现问题，和客户端有关。比如401权限问题、404 URL不存在。</td></tr><tr><td align="left">5XX</td><td align="left">出现问题，和服务端有关。比如500内部错误、504请求超时</td></tr></tbody></table><p>2、响应头，为响应报文附加额外信息，常见响应头key由Content-Type 和 Content-Encoding。<br>3、响应体，请求返回到客户端的正文数据。</p><h2 id="第二部分：Nginx基础配置"><a href="#第二部分：Nginx基础配置" class="headerlink" title="第二部分：Nginx基础配置"></a>第二部分：Nginx基础配置</h2><p><strong>指令介绍</strong><br>1、简单指令：由名称和参数组成，以空格分隔，以分号结尾。（类似变量）<br>2、指令块：由名称和大括号{}内的附件指令组成，不以分号结尾。</p><p>简单指令在指令块中的配置存在一定区段。有些 简单指令不能在某些指令块中使用；有的可以在http块中也可以在server块中，甚至可以在location块中进行配置。当某个变量同时出现在多个指令块中，最终以最小指令块中赋值为准。<br><strong><em>client_boby_timeout 可以在 http、server及location块中设置、server_names_hash_bucket_size 只能出现在http块中。</em></strong></p><ul><li>server_name 支持使用通配符正则表达式，支持配置多域名、服务名称。</li></ul><p>如果存在多个、优先级如下：<br>1、精准的名字<br>2、以<em>开头的最长通配符名称。eg <em>.domian.com<br>3、以</em>结尾的最长通配符名称。eg domian.</em><br>4、按照未见顺序，第一个匹配到正则表达式<br>5、如果没有匹配到对应的server_name，则访问default_server</p><ul><li>URL 在location块中的匹配规则及优先级</li></ul><table><thead><tr><th align="left">location地址</th><th align="left">描述信息</th></tr></thead><tbody><tr><td align="left">location = /url</td><td align="left">= 表示精确匹配</td></tr><tr><td align="left">location ^~ /url</td><td align="left">^~匹配以某个URL前缀开头的请求，不支持正则表达式</td></tr><tr><td align="left">location ~</td><td align="left">~ 区分大小写的匹配，属于正则表达式</td></tr><tr><td align="left">location ~*</td><td align="left">~* 不区分大小写的匹配，属于正则表达式</td></tr><tr><td align="left">location /url</td><td align="left">表示前缀匹配，不带修饰符，但是优先级没有正则表达式高</td></tr><tr><td align="left">location /</td><td align="left">通用匹配，默认找不到其他匹配时，会进行统配匹配</td></tr><tr><td align="left">location @</td><td align="left">命名空间，不提供常规的请求匹配</td></tr></tbody></table><ul><li>只能出现location块的指令</li></ul><p>internal：表示该location块支持Nginx内部的请求访问，比如支持 rewrite、error_page等重定向，但不能通过外部的HTTP直接访问。<br>limit_except：限定该location块可以执行HTTP方法，比如GET。<br>alias：定义指定位置替换</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><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">location /a/ &#123;</span><br><span class="line"> alias /c/x/a;</span><br><span class="line">&#125;</span><br><span class="line"># 如果请求/a/test.json,会变成/c/x/a/test.json</span><br></pre></td></tr></table></figure><p>include 用来指定主配置文件包含的其他扩展配置文件。可以出现在location块、server块任何位置。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;第一部分：Nginx学习必知&quot;&gt;&lt;a href=&quot;#第一部分：Nginx学习必知&quot; class=&quot;headerlink&quot; title=&quot;第一部分：Nginx学习必知&quot;&gt;&lt;/a&gt;第一部分：Nginx学习必知&lt;/h2&gt;&lt;p&gt;Nginx是一个以高性能、高并发著称的HTTP服务器，它支持HTTP（HyperText Transfer Protocol，超文本传输协议）反向代理、TCP（Transmission Control Protocol，传输控制协议）代理、负载均衡、HTTP缓存及Web开发等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTP请求报文&lt;/strong&gt;&lt;br&gt;1、请求行，包括请求方法、请求URL（Uniform Resource Locator，统一资源定位符）、HTTP及其版本号。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP1.1  （PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH）兼容HTTP1.0&lt;/li&gt;
&lt;li&gt;HTTP1.0  （GET、HEAD、POST）等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2、请求头、指客户端向服务器传输请求时附加的一些信息，有key/value组成，使用:隔开。常见key（Cookie、User_Agent、Accept-Encoding）等。&lt;br&gt;3、请求体、一般由POST请求方法进行提交，可以传输图片、文件或者字符串等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTP相应报文&lt;/strong&gt;&lt;br&gt;1、响应行、包含HTTP版本号、状态码、状态码描述。&lt;/p&gt;
    
    </summary>
    
    
      <category term="nginx" scheme="http://www.180716.xyz/categories/nginx/"/>
    
    
  </entry>
  
  <entry>
    <title>Nginx调用ip2region的lua_c</title>
    <link href="http://www.180716.xyz/nginx/nginx/ip2region_lua_c.shtml"/>
    <id>http://www.180716.xyz/nginx/nginx/ip2region_lua_c.shtml</id>
    <published>2020-01-08T11:50:18.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：ip2region准备工作"><a href="#第一部分：ip2region准备工作" class="headerlink" title="第一部分：ip2region准备工作"></a>第一部分：ip2region准备工作</h2><p>GitHub 地址:<a href="https://github.com/lionsoul2014/ip2region" target="_blank" rel="noopener">https://github.com/lionsoul2014/ip2region</a><br>ip2region - 最自由的ip地址查询库，ip到地区的映射库，提供Binary,B树和纯内存三种查询算法，妈妈再也不用担心我的ip地址定位。</p><p>今天的主角是lua_c模块，我们要使用Openresty调用lua查询IP地址定位。</p><p><strong>安装Openresty等环境</strong></p><p>安装环境套件请移步 <a href="https://oneinstack.com/" target="_blank" rel="noopener">https://oneinstack.com/</a><br>Openresty安装目录/usr/local/openresty<br>这里介绍下Openresty采用LuaJit，目前套件中使用的LuaJit2.1对应的Lua5.1版本，固然ip2region的Lua(Ip2region模块的位运算依赖了bit32模块，这个是lua 5.2才开始支持的。)是不能直接使用的。<br>LuaJit安装目录/usr/local/openresty/luajit/include/luajit-2.1</p><p>下载好 GitHub 地址:<a href="https://github.com/lionsoul2014/ip2region" target="_blank" rel="noopener">https://github.com/lionsoul2014/ip2region</a> 源码</p><p><strong>编译ip2region.so文件</strong><br>我们使用到目录binding/lua_c和binding/c目录和ip2region.db文件</p><a id="more"></a><p>将lua_c和c这个目录上传至我们服务器同一个目录,进入lua_c目录，我们要需要修改Makefile</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">CC = gcc</span><br><span class="line">LIBS = -I ../c/ -I /usr/local/openresty/luajit/include/luajit-2.1</span><br><span class="line">FFLAGS = -O2 -Wall -fPIC</span><br><span class="line">SO_FILE = Ip2region.so</span><br><span class="line">LIB_DIR = /usr/local/lib/lua/5.1</span><br></pre></td></tr></table></figure><p>/usr/local/lib/lua/5.1 为lua存放.so文件。我们要将代码生成到此目录。</p><h2 id="第二部分：Openresty调用lua查找ip地址定位"><a href="#第二部分：Openresty调用lua查找ip地址定位" class="headerlink" title="第二部分：Openresty调用lua查找ip地址定位"></a>第二部分：Openresty调用lua查找ip地址定位</h2><p><strong>创建lua存放目录及存放db文件</strong></p><p>在/usr/local/openresty/nginx/conf目录下创建ip2region文件夹，拷贝我们ip2region.db到此目录<br>新建我们的主角searcher.lua</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">---</span></span><br><span class="line"><span class="comment">--- Generated by Lua</span></span><br><span class="line"><span class="comment">--- Created by 水郁枫子</span></span><br><span class="line"><span class="comment">--- DateTime: 2020/1/9 23:50</span></span><br><span class="line"><span class="comment">---</span></span><br><span class="line">ngx.header[<span class="string">'Content-Type'</span>]=<span class="string">"text/plain;charset=UTF-8"</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">--第一步判断IP是否合法</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">checkInvalid</span><span class="params">()</span></span></span><br><span class="line">    <span class="keyword">local</span> headers=ngx.req.get_headers();</span><br><span class="line">    <span class="keyword">local</span> ip=headers[<span class="string">"X-REAL-IP"</span>] <span class="keyword">or</span> headers[<span class="string">"X_FORWARDED_FOR"</span>] <span class="keyword">or</span> ngx.var.remote_addr <span class="keyword">or</span> <span class="string">"0.0.0.0"</span>;</span><br><span class="line">    <span class="keyword">return</span> ip;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">local</span> ip = checkInvalid();</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ip <span class="keyword">then</span></span><br><span class="line">    <span class="comment">--第二步进行IP定位地址</span></span><br><span class="line">    <span class="keyword">local</span> Ip2region,err = <span class="built_in">require</span> <span class="string">"Ip2region"</span>;</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> Ip2region <span class="keyword">then</span></span><br><span class="line">        ngx.<span class="built_in">log</span>(ngx.ERR,<span class="string">"require Ip2region error: "</span>, err);</span><br><span class="line">        ngx.<span class="built_in">print</span>(<span class="string">"require Ip2region error: "</span>, err);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        <span class="keyword">local</span> ip2region,err = Ip2region.new(<span class="string">"/usr/local/openresty/nginx/conf/ip2region/ip2region.db"</span>);</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> ip2region <span class="keyword">then</span></span><br><span class="line">            ngx.<span class="built_in">log</span>(ngx.ERR,<span class="string">"require Ip2region error: "</span>, err);</span><br><span class="line">            ngx.<span class="built_in">print</span>(<span class="string">"require Ip2region error: "</span>, err);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            <span class="keyword">local</span> data,err = ip2region:memorySearch(ip);</span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> data <span class="keyword">then</span></span><br><span class="line">                ngx.<span class="built_in">print</span>(<span class="string">"require Ip2region data error: "</span>, err);</span><br><span class="line">                ngx.<span class="built_in">log</span>(ngx.ERR,<span class="string">"require Ip2region data error: "</span>, err);</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                <span class="keyword">local</span> region = <span class="built_in">string</span>.<span class="built_in">gsub</span>(data.region, <span class="string">"|0"</span>, <span class="string">""</span>);</span><br><span class="line">                    region = <span class="built_in">string</span>.<span class="built_in">gsub</span>(region, <span class="string">"0"</span>, <span class="string">""</span>);</span><br><span class="line">                    region = <span class="built_in">string</span>.<span class="built_in">gsub</span>(region, <span class="string">"|"</span>, <span class="string">"-"</span>);</span><br><span class="line">                ngx.<span class="built_in">print</span>(<span class="built_in">string</span>.<span class="built_in">format</span>(<span class="string">"欢迎你IP:[%s]&lt;br&gt;来自%s的朋友"</span>, ip, region));</span><br><span class="line">            <span class="keyword">end</span>            </span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    ngx.<span class="built_in">print</span>(<span class="string">"IP address is invalid"</span>,ip);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p><strong>Openrsty配置location</strong></p><p>假设我们的域名为<a href="http://www.domian.com" target="_blank" rel="noopener">www.domian.com</a> 那我们修改<a href="http://www.domian.com.conf" target="_blank" rel="noopener">www.domian.com.conf</a> 文件添加location</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><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">location /ip &#123; </span><br><span class="line">    default_type &apos;text/plain&apos;; </span><br><span class="line">    content_by_lua_file /usr/local/openresty/nginx/conf/ip2region/searcher.lua; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>测试检验</strong><br>访问 <a href="http://www.domian.com/ip" target="_blank" rel="noopener">http://www.domian.com/ip</a> 出现一下内容<br>欢迎你IP:[119.123.29.173]来自中国-广东省-深圳市-电信的朋友</p><p>恭喜您，您已经成功、请尽情享用科技带来喜悦吧。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;第一部分：ip2region准备工作&quot;&gt;&lt;a href=&quot;#第一部分：ip2region准备工作&quot; class=&quot;headerlink&quot; title=&quot;第一部分：ip2region准备工作&quot;&gt;&lt;/a&gt;第一部分：ip2region准备工作&lt;/h2&gt;&lt;p&gt;GitHub 地址:&lt;a href=&quot;https://github.com/lionsoul2014/ip2region&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/lionsoul2014/ip2region&lt;/a&gt;&lt;br&gt;ip2region - 最自由的ip地址查询库，ip到地区的映射库，提供Binary,B树和纯内存三种查询算法，妈妈再也不用担心我的ip地址定位。&lt;/p&gt;
&lt;p&gt;今天的主角是lua_c模块，我们要使用Openresty调用lua查询IP地址定位。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安装Openresty等环境&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;安装环境套件请移步 &lt;a href=&quot;https://oneinstack.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://oneinstack.com/&lt;/a&gt;&lt;br&gt;Openresty安装目录/usr/local/openresty&lt;br&gt;这里介绍下Openresty采用LuaJit，目前套件中使用的LuaJit2.1对应的Lua5.1版本，固然ip2region的Lua(Ip2region模块的位运算依赖了bit32模块，这个是lua 5.2才开始支持的。)是不能直接使用的。&lt;br&gt;LuaJit安装目录/usr/local/openresty/luajit/include/luajit-2.1&lt;/p&gt;
&lt;p&gt;下载好 GitHub 地址:&lt;a href=&quot;https://github.com/lionsoul2014/ip2region&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/lionsoul2014/ip2region&lt;/a&gt; 源码&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;编译ip2region.so文件&lt;/strong&gt;&lt;br&gt;我们使用到目录binding/lua_c和binding/c目录和ip2region.db文件&lt;/p&gt;
    
    </summary>
    
    
      <category term="nginx" scheme="http://www.180716.xyz/categories/nginx/"/>
    
    
  </entry>
  
  <entry>
    <title>iptables防火墙管理</title>
    <link href="http://www.180716.xyz/debian/debian/iptables.shtml"/>
    <id>http://www.180716.xyz/debian/debian/iptables.shtml</id>
    <published>2019-12-20T04:50:18.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<p>iptables命令是Linux上常用的防火墙软件，是netfilter项目的一部分。可以直接配置，也可以通过许多前端和图形界面配置。</p><p><strong>1、语法</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables(选项)(参数)</span><br></pre></td></tr></table></figure><p><strong>2、选项</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><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">-t&lt;表&gt;：指定要操纵的表；</span><br><span class="line">-A：向规则链中添加条目；</span><br><span class="line">-D：从规则链中删除条目；</span><br><span class="line">-i：向规则链中插入条目；</span><br><span class="line">-R：替换规则链中的条目；</span><br><span class="line">-L：显示规则链中已有的条目；</span><br><span class="line">-F：清楚规则链中已有的条目；</span><br><span class="line">-X: 用于删除用户自定义的空链</span><br><span class="line">-Z：清空规则链中的数据包计算器和字节计数器；</span><br><span class="line">-N：创建新的用户自定义规则链；</span><br><span class="line">-P：定义规则链中的默认目标；</span><br><span class="line">-h：显示帮助信息；</span><br><span class="line">-p：指定要匹配的数据包协议类型；</span><br><span class="line">-s：指定要匹配的数据包源ip地址；</span><br><span class="line">-d：指定要匹配的数据包源ip地址</span><br><span class="line">-j&lt;目标&gt;：指定要跳转的目标；</span><br><span class="line">-i&lt;网络接口&gt;：指定数据包进入本机的网络接口；</span><br><span class="line">-o&lt;网络接口&gt;：指定数据包要离开本机所使用的网络接口。</span><br></pre></td></tr></table></figure><a id="more"></a><p><strong>3、iptables命令选项输入顺序</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -t 表名 &lt;-A/I/D/R&gt; 规则链名 [规则号] &lt;-i/o 网卡名&gt; -p 协议名 &lt;-s 源IP/源子网&gt; --sport 源端口 &lt;-d 目标IP/目标子网&gt; --dport 目标端口 -j 动作</span><br></pre></td></tr></table></figure><p><strong>表名包括：</strong></p><ul><li>raw：高级功能，如：网址过滤。</li><li>mangle：数据包修改（QOS），用于实现服务质量。</li><li>net：地址转换，用于网关路由器。</li><li>filter：包过滤，用于防火墙规则。</li></ul><p><strong>规则链名包括：</strong></p><ul><li>INPUT链：处理输入数据包。</li><li>OUTPUT链：处理输出数据包。</li><li>PORWARD链：处理转发数据包。</li><li>PREROUTING链：用于目标地址转换（DNAT）。</li><li>POSTOUTING链：用于源地址转换（SNAT）。</li></ul><p><strong>动作包括：</strong></p><ul><li>accept：接收数据包。</li><li>DROP：丢弃数据包。</li><li>REDIRECT：重定向、映射、透明代理。</li><li>SNAT：源地址转换。</li><li>DNAT：目标地址转换。</li><li>MASQUERADE：IP伪装（NAT），用于ADSL。</li><li>LOG：日志记录。</li></ul><p><strong>4、实例</strong></p><p><em>清除已有iptables规则</em></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">iptables -F</span><br><span class="line">iptables -X</span><br><span class="line">iptables -Z</span><br></pre></td></tr></table></figure><p><em>开放指定的端口</em></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT               <span class="comment">#允许本地回环接口(即运行本机访问本机)</span></span><br><span class="line">iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT    <span class="comment">#允许已建立的或相关连的通行</span></span><br><span class="line">iptables -A OUTPUT -j ACCEPT         <span class="comment">#允许所有本机向外的访问</span></span><br><span class="line">iptables -A INPUT -p tcp --dport 22 -j ACCEPT    <span class="comment">#允许访问22端口</span></span><br><span class="line">iptables -A INPUT -p tcp --dport 80 -j ACCEPT    <span class="comment">#允许访问80端口</span></span><br><span class="line">iptables -A INPUT -p tcp --dport 21 -j ACCEPT    <span class="comment">#允许ftp服务的21端口</span></span><br><span class="line">iptables -A INPUT -p tcp --dport 20 -j ACCEPT    <span class="comment">#允许FTP服务的20端口</span></span><br><span class="line">iptables -A INPUT -j reject       <span class="comment">#禁止其他未允许的规则访问</span></span><br><span class="line">iptables -A FORWARD -j REJECT     <span class="comment">#禁止其他未允许的规则访问</span></span><br></pre></td></tr></table></figure><p><em>屏蔽IP</em></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">iptables -A INPUT -s pastebin.com -j DROP     <span class="comment">#屏蔽本机访问pastebin.com的命令</span></span><br><span class="line">iptables -A OUTPUT -d pastebin.com -j DROP    <span class="comment">#屏蔽pastebin.com访问本机的命令</span></span><br><span class="line">iptables -I INPUT -s 123.45.6.7 -j DROP       <span class="comment">#屏蔽单个IP的命令</span></span><br><span class="line">iptables -I INPUT -s 123.0.0.0/8 -j DROP      <span class="comment">#封整个段即从123.0.0.1到123.255.255.254的命令</span></span><br><span class="line">iptables -I INPUT -s 124.45.0.0/16 -j DROP    <span class="comment">#封IP段即从123.45.0.1到123.45.255.254的命令</span></span><br><span class="line">iptables -I INPUT -s 123.45.6.0/24 -j DROP    <span class="comment">#封IP段即从123.45.6.1到123.45.6.254的命令是</span></span><br></pre></td></tr></table></figure><p><em>查看已添加的iptables规则</em></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">iptables -L -n -v</span><br><span class="line">Chain INPUT (policy DROP 48106 packets, 2690K bytes)</span><br><span class="line"> pkts bytes target     prot opt <span class="keyword">in</span>     out     <span class="built_in">source</span>               destination         </span><br><span class="line"> 5075  589K ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           </span><br><span class="line"> 191K   90M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22</span><br><span class="line">1499K  133M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80</span><br><span class="line">4364K 6351M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED</span><br><span class="line"> 6256  327K ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           </span><br><span class="line"></span><br><span class="line">Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)</span><br><span class="line"> pkts bytes target     prot opt <span class="keyword">in</span>     out     <span class="built_in">source</span>               destination         </span><br><span class="line"></span><br><span class="line">Chain OUTPUT (policy ACCEPT 3382K packets, 1819M bytes)</span><br><span class="line"> pkts bytes target     prot opt <span class="keyword">in</span>     out     <span class="built_in">source</span>               destination         </span><br><span class="line"> 5075  589K ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0</span><br></pre></td></tr></table></figure><p><strong>5、删除已添加的iptables规则</strong></p><p><em>将所有iptables以序号标记显示，执行：</em></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -L -n --line-numbers</span><br></pre></td></tr></table></figure><p><em>比如要删除INPUT里序号为8的规则，执行：</em></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -D INPUT 8</span><br></pre></td></tr></table></figure><p><strong>6、将防火墙记录保存</strong></p><ul><li>1、保存iptables现有规则到/etc/iptables.up.rules</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables-save &gt; /etc/iptables.up.rules</span><br></pre></td></tr></table></figure><ul><li>2、建立系统启动加载文件/etc/network/if-pre-up.d/iptables</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/network/<span class="keyword">if</span>-pre-up.d/iptables</span><br></pre></td></tr></table></figure><p>输入以下内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line">/sbin/iptables-restore &lt; /etc/iptables.up.rules</span><br></pre></td></tr></table></figure><ul><li>3、让文件具备执行权限</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chmod +x /etc/network/<span class="keyword">if</span>-pre-up.d/iptables</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;iptables命令是Linux上常用的防火墙软件，是netfilter项目的一部分。可以直接配置，也可以通过许多前端和图形界面配置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1、语法&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;iptables(选项)(参数)&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;2、选项&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;13&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;14&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;15&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;16&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;17&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;18&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;-t&amp;lt;表&amp;gt;：指定要操纵的表；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-A：向规则链中添加条目；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-D：从规则链中删除条目；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-i：向规则链中插入条目；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-R：替换规则链中的条目；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-L：显示规则链中已有的条目；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-F：清楚规则链中已有的条目；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-X: 用于删除用户自定义的空链&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-Z：清空规则链中的数据包计算器和字节计数器；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-N：创建新的用户自定义规则链；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-P：定义规则链中的默认目标；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-h：显示帮助信息；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-p：指定要匹配的数据包协议类型；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-s：指定要匹配的数据包源ip地址；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-d：指定要匹配的数据包源ip地址&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-j&amp;lt;目标&amp;gt;：指定要跳转的目标；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-i&amp;lt;网络接口&amp;gt;：指定数据包进入本机的网络接口；&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;-o&amp;lt;网络接口&amp;gt;：指定数据包要离开本机所使用的网络接口。&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="debian" scheme="http://www.180716.xyz/categories/debian/"/>
    
    
  </entry>
  
  <entry>
    <title>Linux中Solr8.3设置登录密码</title>
    <link href="http://www.180716.xyz/solr/solr/solr_admin_realm.shtml"/>
    <id>http://www.180716.xyz/solr/solr/solr_admin_realm.shtml</id>
    <published>2019-12-19T14:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：Solr配置账户密码"><a href="#第一部分：Solr配置账户密码" class="headerlink" title="第一部分：Solr配置账户密码"></a>第一部分：Solr配置账户密码</h2><p><strong>创建配置文件</strong></p><p>/data/solr-8.3.0/server/etc<br>创建realm.properties</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">#  </span><br><span class="line"># 这个文件定义用户名,密码和角色</span><br><span class="line">#  </span><br><span class="line"># 格式如下  </span><br><span class="line">#  &lt;username&gt;: &lt;password&gt;[,&lt;rolename&gt; ...]  </span><br><span class="line">#  </span><br><span class="line">#userName: password,role  </span><br><span class="line">admin: passwd1219,admin</span><br></pre></td></tr></table></figure><p><strong>安全处理程序设置</strong></p><p>/data/solr-8.3.0/server/contexts<br>修改solr-jetty-context.xml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version="1.0"?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">Configure</span> <span class="attr">class</span>=<span class="string">"org.eclipse.jetty.webapp.WebAppContext"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"contextPath"</span>&gt;</span><span class="tag">&lt;<span class="name">Property</span> <span class="attr">name</span>=<span class="string">"hostContext"</span> <span class="attr">default</span>=<span class="string">"/solr"</span>/&gt;</span><span class="tag">&lt;/<span class="name">Set</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"war"</span>&gt;</span><span class="tag">&lt;<span class="name">Property</span> <span class="attr">name</span>=<span class="string">"jetty.base"</span>/&gt;</span>/solr-webapp/webapp<span class="tag">&lt;/<span class="name">Set</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"defaultsDescriptor"</span>&gt;</span><span class="tag">&lt;<span class="name">Property</span> <span class="attr">name</span>=<span class="string">"jetty.base"</span>/&gt;</span>/etc/webdefault.xml<span class="tag">&lt;/<span class="name">Set</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"extractWAR"</span>&gt;</span>false<span class="tag">&lt;/<span class="name">Set</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 安全处理程序设置 --&gt;</span>  </span><br><span class="line">  <span class="tag">&lt;<span class="name">Get</span> <span class="attr">name</span>=<span class="string">"securityHandler"</span>&gt;</span>  </span><br><span class="line">         <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"loginService"</span>&gt;</span>  </span><br><span class="line">                 <span class="tag">&lt;<span class="name">New</span> <span class="attr">class</span>=<span class="string">"org.eclipse.jetty.security.HashLoginService"</span>&gt;</span>  </span><br><span class="line">                         <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"name"</span>&gt;</span>realm<span class="tag">&lt;/<span class="name">Set</span>&gt;</span>  <span class="comment">&lt;!-- 一个名字--&gt;</span></span><br><span class="line">　　　　　　　　　　　　　　<span class="comment">&lt;!-- 引入刚刚新建的文件 --&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">Set</span> <span class="attr">name</span>=<span class="string">"config"</span>&gt;</span><span class="tag">&lt;<span class="name">SystemProperty</span> <span class="attr">name</span>=<span class="string">"jetty.home"</span> <span class="attr">default</span>=<span class="string">"."</span>/&gt;</span>/etc/realm.properties<span class="tag">&lt;/<span class="name">Set</span>&gt;</span>  </span><br><span class="line">                 <span class="tag">&lt;/<span class="name">New</span>&gt;</span>  </span><br><span class="line">         <span class="tag">&lt;/<span class="name">Set</span>&gt;</span>  </span><br><span class="line">  <span class="tag">&lt;/<span class="name">Get</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">Configure</span>&gt;</span></span><br></pre></td></tr></table></figure><a id="more"></a><p><strong>添加验证拦截</strong><br>/data/solr-8.3.0/server/solr-webapp/webapp/WEB-INF<br>编辑web.xml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">security-constraint</span>&gt;</span>    </span><br><span class="line">　　<span class="tag">&lt;<span class="name">web-resource-collection</span>&gt;</span>    </span><br><span class="line">    　　<span class="tag">&lt;<span class="name">web-resource-name</span>&gt;</span>Solr<span class="tag">&lt;/<span class="name">web-resource-name</span>&gt;</span> <span class="comment">&lt;!--描述--&gt;</span>   </span><br><span class="line">    　　<span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span>                <span class="comment">&lt;!-- 验证的网页的位置--&gt;</span>    </span><br><span class="line">    <span class="tag">&lt;/<span class="name">web-resource-collection</span>&gt;</span>    </span><br><span class="line">     <span class="tag">&lt;<span class="name">auth-constraint</span>&gt;</span>    </span><br><span class="line">        <span class="tag">&lt;<span class="name">role-name</span>&gt;</span>admin<span class="tag">&lt;/<span class="name">role-name</span>&gt;</span>                <span class="comment">&lt;!-- 验证的角色，别写成用户名，如有多个角色可以写多个role-name 标签--&gt;</span>    </span><br><span class="line">     <span class="tag">&lt;/<span class="name">auth-constraint</span>&gt;</span>    </span><br><span class="line"> <span class="tag">&lt;/<span class="name">security-constraint</span>&gt;</span>    </span><br><span class="line"> <span class="tag">&lt;<span class="name">login-config</span>&gt;</span>    </span><br><span class="line">        <span class="tag">&lt;<span class="name">auth-method</span>&gt;</span>BASIC<span class="tag">&lt;/<span class="name">auth-method</span>&gt;</span>            <span class="comment">&lt;!-- 关键--&gt;</span>    </span><br><span class="line">        <span class="tag">&lt;<span class="name">realm-name</span>&gt;</span>realm<span class="tag">&lt;/<span class="name">realm-name</span>&gt;</span>              <span class="comment">&lt;!-- solr-jetty-context.xml中name标签内容--&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">login-config</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="第二部分：测试与验证"><a href="#第二部分：测试与验证" class="headerlink" title="第二部分：测试与验证"></a>第二部分：测试与验证</h2><p>再次访问已经要输入用户名密码才可以操作了</p><p><img src="/upload/solr/solr_index_page.png" alt="alt text" title="Solr Admin UI页面"></p><p>如果Java集成solr地址如下：</p><p><a href="http://admin:passwd1219@localhost:8983/solr/new_core" target="_blank" rel="noopener">http://admin:passwd1219@localhost:8983/solr/new_core</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;第一部分：Solr配置账户密码&quot;&gt;&lt;a href=&quot;#第一部分：Solr配置账户密码&quot; class=&quot;headerlink&quot; title=&quot;第一部分：Solr配置账户密码&quot;&gt;&lt;/a&gt;第一部分：Solr配置账户密码&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;创建配置文件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;/data/solr-8.3.0/server/etc&lt;br&gt;创建realm.properties&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;#  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;# 这个文件定义用户名,密码和角色&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;#  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;# 格式如下  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;#  &amp;lt;username&amp;gt;: &amp;lt;password&amp;gt;[,&amp;lt;rolename&amp;gt; ...]  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;#  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;#userName: password,role  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;admin: passwd1219,admin&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;安全处理程序设置&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;/data/solr-8.3.0/server/contexts&lt;br&gt;修改solr-jetty-context.xml&lt;/p&gt;
&lt;figure class=&quot;highlight xml&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;13&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;14&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;15&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;16&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;17&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;18&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;meta&quot;&gt;&amp;lt;!DOCTYPE Configure PUBLIC &quot;-//Jetty//Configure//EN&quot; &quot;http://www.eclipse.org/jetty/configure_9_0.dtd&quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Configure&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;org.eclipse.jetty.webapp.WebAppContext&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;contextPath&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Property&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;hostContext&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;default&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;/solr&quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;war&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Property&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;jetty.base&quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;/solr-webapp/webapp&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;defaultsDescriptor&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Property&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;jetty.base&quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;/etc/webdefault.xml&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;extractWAR&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;false&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;&amp;lt;!-- 安全处理程序设置 --&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Get&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;securityHandler&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;         &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;loginService&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;                 &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;New&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;org.eclipse.jetty.security.HashLoginService&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;                         &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;name&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;realm&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;comment&quot;&gt;&amp;lt;!-- 一个名字--&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;　　　　　　　　　　　　　　&lt;span class=&quot;comment&quot;&gt;&amp;lt;!-- 引入刚刚新建的文件 --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;                        &lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;config&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;&lt;span class=&quot;name&quot;&gt;SystemProperty&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;jetty.home&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;default&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&quot;.&quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;/etc/realm.properties&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;                 &lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;New&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;         &lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Set&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Get&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/&lt;span class=&quot;name&quot;&gt;Configure&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="solr" scheme="http://www.180716.xyz/categories/solr/"/>
    
    
  </entry>
  
  <entry>
    <title>thymeleaf学习笔记</title>
    <link href="http://www.180716.xyz/thymeleaf/thymeleaf/thymeleaf_learn.shtml"/>
    <id>http://www.180716.xyz/thymeleaf/thymeleaf/thymeleaf_learn.shtml</id>
    <published>2019-12-11T04:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：Thymeleaf介绍"><a href="#第一部分：Thymeleaf介绍" class="headerlink" title="第一部分：Thymeleaf介绍"></a>第一部分：Thymeleaf介绍</h2><p>  简单说，Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎，它可以完全替代 JSP 。相较与其他的模板引擎，它有如下三个极吸引人的特点：<br>  1.Thymeleaf 在有网络和无网络的环境下皆可运行，即它可以让美工在浏览器查看页面的静态效果，也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型，然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性，所以 Thymeleaf 的模板可以静态地运行；当有数据返回到页面时，Thymeleaf 标签会动态地替换掉静态内容，使页面动态显示。<br>  2.Thymeleaf 开箱即用的特性。它提供标准和 Spring 标准两种方言，可以直接套用模板实现 JSTL、 OGNL表达式效果，避免每天套模板、改 Jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。<br>  3.Thymeleaf 提供 Spring 标准方言和一个与 SpringMVC 完美集成的可选模块，可以快速的实现表单绑定、属性编辑器、国际化等功能。</p><h2 id="第二部分：常用命令介绍"><a href="#第二部分：常用命令介绍" class="headerlink" title="第二部分：常用命令介绍"></a>第二部分：常用命令介绍</h2><p><strong>utext及text使用</strong><br>th:utext和th:text的区别是：th:text会对&lt;和&gt;进行转义，而th:utext不会转义。</p><a id="more"></a><p>eg.. 国际化文件中 welcome.info=欢迎您{0}登录系统！</p><figure class="highlight html"><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">#admin 页面中变量</span><br><span class="line"><span class="tag">&lt;<span class="name">h2</span> <span class="attr">th:text</span>=<span class="string">"#&#123;welcome.info('admin')&#125;"</span>/&gt;</span></span><br></pre></td></tr></table></figure><p>eg. utext进行一下简单运算</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'数学计算：1+2=' + (1 + 2)"</span>/&gt;</span></span><br></pre></td></tr></table></figure><p><strong>$及*区别及使用</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"> # user为后台传输对象 </span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'用户姓名：' + $&#123;user.name&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'用户年龄：' + $&#123;user.age&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'出生日期：' + $&#123;#dates.format(user.birthday,'yyyy-MM-dd')&#125;"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:object</span>=<span class="string">"$&#123;user&#125;"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'用户姓名：' + *&#123;name&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'用户年龄：' + *&#123;age&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'出生日期：' + *&#123;#dates.format(birthday,'yyyy-MM-dd')&#125;"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>日期、字符串、集合使用</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#dates.format(mydate,'yyyy-MM-dd')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#dates.format(mydate,'yyyy-MM-dd HH:mm:ss.SSS')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#strings.replace('www.baidu.cn','.','$')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#strings.toUpperCase('www.baidu.cn')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#strings.trim('www.baidu.cn')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#sets.contains(names,'boot-0')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#sets.contains(names,'boot-9')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#sets.size(names)&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#sets.contains(ids,0)&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;ids[1]&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;names[1]&#125;"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>@{}使用</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">th:src</span>=<span class="string">"@&#123;/js/main.js&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">"@&#123;/show&#125;"</span>&gt;</span>访问controller方法<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">"@&#123;/static_index.html&#125;"</span>&gt;</span>访问静态页面<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>操作内置对象</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE HTML&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">xmlns:th</span>=<span class="string">"http://www.thymeleaf.org"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>SpringBoot模版渲染<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">th:src</span>=<span class="string">"@&#123;/js/main.js&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"Content-Type"</span> <span class="attr">content</span>=<span class="string">"text/html;charset=UTF-8"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#httpServletRequest.getRemoteAddr()&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#httpServletRequest.getAttribute('requestMessage')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#httpSession.getId()&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"$&#123;#httpServletRequest.getServletContext().getRealPath('/')&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'requestMessage = ' + $&#123;requestMessage&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'sessionMessage = ' + $&#123;session.sessionMessage&#125;"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">th:text</span>=<span class="string">"'applicationMessage = ' + $&#123;application.applicationMessage&#125;"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>逻辑处理</strong><br>and、or、关系比较（&gt;、&lt;、&gt;=、&lt;=、==、!=、lt、gt、le、ge、eq、ne）。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">#满足情况下th:if</span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">th:if</span>=<span class="string">"$&#123;member.age lt 18&#125;"</span>&gt;</span></span><br><span class="line">未成年人！</span><br><span class="line"><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">th:if</span>=<span class="string">"$&#123;member.name eq '啊三'&#125;"</span>&gt;</span></span><br><span class="line">欢迎小三来访问！</span><br><span class="line"><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#不满足情况下th:unless</span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">th:unless</span>=<span class="string">"$&#123;member.age gt 18&#125;"</span>&gt;</span></span><br><span class="line">你还不满18岁，不能够看电影！</span><br><span class="line"><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#switch选择语句th:switch</span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">th:switch</span>=<span class="string">"$&#123;member.uid&#125;"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">th:case</span>=<span class="string">"100"</span>&gt;</span>uid为101的员工来了<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">th:case</span>=<span class="string">"99"</span>&gt;</span>uid为102的员工来了<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">th:case</span>=<span class="string">"*"</span>&gt;</span>没有匹配成功的数据！<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>数据遍历</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">#list集合遍历</span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>No.<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>UID<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>姓名<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>年龄<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>偶数<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>奇数<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span> <span class="attr">th:each</span>=<span class="string">"user,memberStat:$&#123;allUsers&#125;"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberStat.index + 1&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;user.uid&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;user.name&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;user.age&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberStat.even&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberStat.odd&#125;"</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#map集合遍历</span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>No.<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>KEY<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>UID<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>姓名<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>年龄<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>偶数<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>奇数<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span> <span class="attr">th:each</span>=<span class="string">"memberEntry,memberStat:$&#123;allUsers&#125;"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberStat.index + 1&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberEntry.key&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberEntry.value.uid&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberEntry.value.name&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberEntry.value.age&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberStat.even&#125;"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">"$&#123;memberStat.odd&#125;"</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#数字遍历</span><br><span class="line"># eg. 比如我们要写一个月份的下拉列表</span><br><span class="line"><span class="tag">&lt;<span class="name">option</span> <span class="attr">th:each</span>=<span class="string">"i:$&#123;#numbers.sequence(1, 28)&#125;"</span> <span class="attr">th:value</span>=<span class="string">"$&#123;i&#125;"</span> <span class="attr">th:utext</span>=<span class="string">"'每月'+$&#123;i&#125;+'号'"</span>&gt;</span><span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>页面引入</strong></p><p>关于thymeleaf th:replace th:include th:insert 的区别<br>th:insert  ：保留自己的主标签，保留th:fragment的主标签。<br>th:replace ：不要自己的主标签，保留th:fragment的主标签。<br>th:include ：保留自己的主标签，不要th:fragment的主标签。（官方3.0后不推荐）</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">需要替换的片段内容：</span><br><span class="line"><span class="tag">&lt;<span class="name">footer</span> <span class="attr">th:fragment</span>=<span class="string">"copy"</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">th:src</span>=<span class="string">"@&#123;/plugins/jquery/jquery-3.0.2.js&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"> </span><br><span class="line">导入片段： </span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">th:insert</span>=<span class="string">"footer::copy"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">th:replace</span>=<span class="string">"footer::copy"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">th:include</span>=<span class="string">"footer::copy"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span>  </span><br><span class="line"> </span><br><span class="line">结果为： </span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">th:src</span>=<span class="string">"@&#123;/plugins/jquery/jquery-3.0.2.js&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">footer</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">th:src</span>=<span class="string">"@&#123;/plugins/jquery/jquery-3.0.2.js&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">footer</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">th:src</span>=<span class="string">"@&#123;/plugins/jquery/jquery-3.0.2.js&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;第一部分：Thymeleaf介绍&quot;&gt;&lt;a href=&quot;#第一部分：Thymeleaf介绍&quot; class=&quot;headerlink&quot; title=&quot;第一部分：Thymeleaf介绍&quot;&gt;&lt;/a&gt;第一部分：Thymeleaf介绍&lt;/h2&gt;&lt;p&gt;  简单说，Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎，它可以完全替代 JSP 。相较与其他的模板引擎，它有如下三个极吸引人的特点：&lt;br&gt;  1.Thymeleaf 在有网络和无网络的环境下皆可运行，即它可以让美工在浏览器查看页面的静态效果，也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型，然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性，所以 Thymeleaf 的模板可以静态地运行；当有数据返回到页面时，Thymeleaf 标签会动态地替换掉静态内容，使页面动态显示。&lt;br&gt;  2.Thymeleaf 开箱即用的特性。它提供标准和 Spring 标准两种方言，可以直接套用模板实现 JSTL、 OGNL表达式效果，避免每天套模板、改 Jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。&lt;br&gt;  3.Thymeleaf 提供 Spring 标准方言和一个与 SpringMVC 完美集成的可选模块，可以快速的实现表单绑定、属性编辑器、国际化等功能。&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;&lt;p&gt;&lt;strong&gt;utext及text使用&lt;/strong&gt;&lt;br&gt;th:utext和th:text的区别是：th:text会对&amp;lt;和&amp;gt;进行转义，而th:utext不会转义。&lt;/p&gt;
    
    </summary>
    
    
      <category term="thymeleaf" scheme="http://www.180716.xyz/categories/thymeleaf/"/>
    
    
  </entry>
  
  <entry>
    <title>websocket服务端支持ssl</title>
    <link href="http://www.180716.xyz/netty/netty/websocket_ssl.shtml"/>
    <id>http://www.180716.xyz/netty/netty/websocket_ssl.shtml</id>
    <published>2019-12-01T06:36:30.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<h4 id="为什么要使用ssl-wss连接"><a href="#为什么要使用ssl-wss连接" class="headerlink" title="为什么要使用ssl(wss连接)"></a>为什么要使用ssl(wss连接)</h4><p>鉴于目前websocket使用情况，部分人将其使用到带有https的网站上（ws连接）就会无法连接（当然你可以选择在浏览器上选择加载不安全脚本解决）。为了长远目标考虑还是选择让我们websocket支持ssl。如果让我们的websocket支持ssl需要如何操作呢，有两种方式第一种是让我们的程序（websocket支持ssl）本文暂时不介绍。本文采用第二种方式使用nginx反向代理支持ssl。</p><h4 id="开始实际操作"><a href="#开始实际操作" class="headerlink" title="开始实际操作"></a>开始实际操作</h4><p><strong>1、你的nginx支持https访问</strong><br>如果没有支持https访问那么首先将你的网站修改为https方法。<br>证书获取方式介绍给大家<br>1、你可以通过网站进行获取 <a href="https://freessl.cn/" target="_blank" rel="noopener">https://freessl.cn/</a><br>2、如果你是阿里云、腾讯云等你可以通过控制中心申请属于你自己的证书</p><a id="more"></a><p><strong>2、开始操练起来</strong></p><p>修改自己网站.conf文件</p><p>反向代理配置/ws_protocol 为自定义websocket地址信息</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#此处省略其他配置信息</span></span><br><span class="line">    </span><br><span class="line">    location /ws_protocol &#123;      </span><br><span class="line">      proxy_redirect off;</span><br><span class="line">      proxy_pass http://wss_svr;      <span class="comment"># 转发</span></span><br><span class="line">      proxy_set_header X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">      proxy_set_header X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">      proxy_set_header Host <span class="variable">$http_host</span>;</span><br><span class="line">      proxy_set_header X-NginX-Proxy <span class="literal">true</span>;</span><br><span class="line">      proxy_http_version 1.1;</span><br><span class="line">      proxy_set_header Upgrade <span class="variable">$http_upgrade</span>;   <span class="comment"># 升级协议头</span></span><br><span class="line">      proxy_set_header Connection upgrade;</span><br><span class="line">      proxy_read_timeout 600s;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>地址信息配置，此配置信息在http 节点内即可。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#此处省略其他配置信息</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 实际websocket服务器地址</span></span><br><span class="line">    upstream wss_svr &#123;</span><br><span class="line">        server 127.0.0.1:5052 weight=1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意:wss_svr配置在http括号内，反向代理信息配置在server括号内。server在http内。</p>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;为什么要使用ssl-wss连接&quot;&gt;&lt;a href=&quot;#为什么要使用ssl-wss连接&quot; class=&quot;headerlink&quot; title=&quot;为什么要使用ssl(wss连接)&quot;&gt;&lt;/a&gt;为什么要使用ssl(wss连接)&lt;/h4&gt;&lt;p&gt;鉴于目前websocket使用情况，部分人将其使用到带有https的网站上（ws连接）就会无法连接（当然你可以选择在浏览器上选择加载不安全脚本解决）。为了长远目标考虑还是选择让我们websocket支持ssl。如果让我们的websocket支持ssl需要如何操作呢，有两种方式第一种是让我们的程序（websocket支持ssl）本文暂时不介绍。本文采用第二种方式使用nginx反向代理支持ssl。&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;&lt;p&gt;&lt;strong&gt;1、你的nginx支持https访问&lt;/strong&gt;&lt;br&gt;如果没有支持https访问那么首先将你的网站修改为https方法。&lt;br&gt;证书获取方式介绍给大家&lt;br&gt;1、你可以通过网站进行获取 &lt;a href=&quot;https://freessl.cn/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://freessl.cn/&lt;/a&gt;&lt;br&gt;2、如果你是阿里云、腾讯云等你可以通过控制中心申请属于你自己的证书&lt;/p&gt;
    
    </summary>
    
    
      <category term="netty" scheme="http://www.180716.xyz/categories/netty/"/>
    
    
  </entry>
  
  <entry>
    <title>websocket服务端功能(双向消息、群组)</title>
    <link href="http://www.180716.xyz/netty/netty/websocket.shtml"/>
    <id>http://www.180716.xyz/netty/netty/websocket.shtml</id>
    <published>2019-11-26T06:36:30.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="WebSocket介绍"><a href="#WebSocket介绍" class="headerlink" title="WebSocket介绍"></a>WebSocket介绍</h3><p>WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455，并由RFC7936补充规范。WebSocket API也被W3C定为标准。<br>WebSocket使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。在WebSocket API中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接，并进行双向数据传输。</p><h3 id="直接开始进入正题–SpringBoot-WebSocket-开始"><a href="#直接开始进入正题–SpringBoot-WebSocket-开始" class="headerlink" title="直接开始进入正题–SpringBoot WebSocket 开始"></a>直接开始进入正题–SpringBoot WebSocket 开始</h3><p><strong>1、搭建环境</strong><br>你还在手动搭建项目码？都9102年了还在手动，我们早都全自动了。不会的请戳这里<a href="https://start.spring.io/" target="_blank" rel="noopener">https://start.spring.io/</a></p><a id="more"></a><p><img src="/upload/netty/start_spring_project.png" alt="alt text" title="在线搭建springboot项目"></p><p>点击生成，浏览器会下载一个压缩包。这就是你要的项目了。是不是很简单、很easy、很nice。</p><p><strong>2、准备工作</strong></p><p>项目采用IDEA + Maven + JDK1.8 + Netty4.1.43<br><a href="https://mvnrepository.com/artifact/io.netty/netty-all/4.1.43.Final" target="_blank" rel="noopener">https://mvnrepository.com/artifact/io.netty/netty-all/4.1.43.Final</a></p><p>maven地址如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/io.netty/netty-all --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.netty<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>netty-all<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.1.43.Final<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>3、开始集成Netty</strong></p><p>websocket启动类<br>我们使用的实现ApplicationRunner进行项目启动加载启动我们的netty服务。当然实现CommandLineRunner也可以，他两个区别在于run方法输入参数（封装获取方式），大家自行斟酌自行选择。<br>还有一种方式就是@PostConstruct注解在启动的方法上也可以，但是我在使用springboot scheduling(定时器)时发现定时器不会初始化不会触发。我也是百思不得其姐，SO放弃了…</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.laowj.websocket;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.laowj.websocket.handler.WebSocketServerHandler;</span><br><span class="line"><span class="keyword">import</span> io.netty.bootstrap.ServerBootstrap;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.Channel;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelInitializer;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelPipeline;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.EventLoopGroup;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.nio.NioEventLoopGroup;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.SocketChannel;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.nio.NioServerSocketChannel;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.HttpObjectAggregator;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.HttpServerCodec;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.logging.LogLevel;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.logging.LoggingHandler;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.stream.ChunkedWriteHandler;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.ApplicationArguments;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.ApplicationRunner;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * web socket 服务类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebSocketService</span> <span class="keyword">implements</span> <span class="title">ApplicationRunner</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;websocket.port&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> socketPort;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">(ApplicationArguments args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        EventLoopGroup bossGroup = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        EventLoopGroup workerGroup = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            ServerBootstrap b = <span class="keyword">new</span> ServerBootstrap();</span><br><span class="line">            b.group(bossGroup, workerGroup)</span><br><span class="line">                    .channel(NioServerSocketChannel<span class="class">.<span class="keyword">class</span>)</span></span><br><span class="line"><span class="class">                    .<span class="title">childHandler</span>(<span class="title">new</span> <span class="title">ChannelInitializer</span>&lt;<span class="title">SocketChannel</span>&gt;() </span>&#123;</span><br><span class="line">                        <span class="meta">@Override</span></span><br><span class="line">                        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span></span></span><br><span class="line"><span class="function">                                <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                            ChannelPipeline pipeline = ch.pipeline();</span><br><span class="line">                            pipeline.addLast(<span class="string">"http-codec"</span>,</span><br><span class="line">                                    <span class="keyword">new</span> HttpServerCodec());</span><br><span class="line">                            pipeline.addLast(<span class="string">"aggregator"</span>,</span><br><span class="line">                                    <span class="keyword">new</span> HttpObjectAggregator(<span class="number">65536</span>));</span><br><span class="line">                            pipeline.addLast(<span class="string">"http-chunked"</span>,</span><br><span class="line">                                    <span class="keyword">new</span> ChunkedWriteHandler());</span><br><span class="line">                            pipeline.addLast(<span class="string">"handler"</span>,</span><br><span class="line">                                    <span class="keyword">new</span> WebSocketServerHandler());</span><br><span class="line">                            pipeline.addLast(<span class="string">"logger"</span>,<span class="keyword">new</span> LoggingHandler(LogLevel.INFO));</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;);</span><br><span class="line"></span><br><span class="line">            Channel ch = b.bind(socketPort).sync().channel();</span><br><span class="line">            System.out.println(<span class="string">"Web socket server started at port "</span> + socketPort</span><br><span class="line">                    + <span class="string">'.'</span>);</span><br><span class="line">            System.out</span><br><span class="line">                    .println(<span class="string">"Open your browser and navigate to http://localhost:"</span></span><br><span class="line">                            + socketPort + <span class="string">'/'</span>);</span><br><span class="line"></span><br><span class="line">            ch.closeFuture().sync();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            bossGroup.shutdownGracefully();</span><br><span class="line">            workerGroup.shutdownGracefully();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>重点来了、这块需要那笔记、敲黑板划重点。考试要考的<br>websocket消息处理类WebSocketServerHandler</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.laowj.websocket.handler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.ByteBuf;</span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.Unpooled;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelFuture;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelFutureListener;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandlerContext;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.SimpleChannelInboundHandler;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.group.ChannelGroup;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.group.DefaultChannelGroup;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.DefaultFullHttpResponse;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.FullHttpRequest;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.FullHttpResponse;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.QueryStringDecoder;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.http.websocketx.*;</span><br><span class="line"><span class="keyword">import</span> io.netty.util.Attribute;</span><br><span class="line"><span class="keyword">import</span> io.netty.util.AttributeKey;</span><br><span class="line"><span class="keyword">import</span> io.netty.util.CharsetUtil;</span><br><span class="line"><span class="keyword">import</span> io.netty.util.concurrent.GlobalEventExecutor;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ConcurrentHashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.logging.Level;</span><br><span class="line"><span class="keyword">import</span> java.util.logging.Logger;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> io.netty.handler.codec.http.HttpHeaderNames.HOST;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> io.netty.handler.codec.http.HttpMethod.GET;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> io.netty.handler.codec.http.HttpResponseStatus.*;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> io.netty.handler.codec.http.HttpUtil.isKeepAlive;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> io.netty.handler.codec.http.HttpUtil.setContentLength;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> io.netty.handler.codec.http.HttpVersion.HTTP_1_1;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebSocketServerHandler</span> <span class="keyword">extends</span> <span class="title">SimpleChannelInboundHandler</span>&lt;<span class="title">Object</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger logger = Logger</span><br><span class="line">            .getLogger(WebSocketServerHandler<span class="class">.<span class="keyword">class</span>.<span class="title">getName</span>())</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> WebSocketServerHandshaker handshaker;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// websocket 服务的 uri</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String WEBSOCKET_PATH = <span class="string">"/ws_protocol"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 一个 ChannelGroup 代表一个频道</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Map&lt;String, ChannelGroup&gt; channelGroupMap = <span class="keyword">new</span> ConcurrentHashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 本次请求的 code</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String HTTP_REQUEST_STRING = <span class="string">"token"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 存储token</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> AttributeKey&lt;String&gt; TOKEN_CHANNEL_KEYS = AttributeKey.valueOf(<span class="string">"TOKEN.CHANNEL.KEYS"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">channelRead0</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">// 传统的HTTP接入</span></span><br><span class="line">        <span class="keyword">if</span> (msg <span class="keyword">instanceof</span> FullHttpRequest) &#123;</span><br><span class="line">            handleHttpRequest(ctx, (FullHttpRequest) msg);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// WebSocket接入</span></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (msg <span class="keyword">instanceof</span> WebSocketFrame) &#123;</span><br><span class="line">            handleWebSocketFrame(ctx, (WebSocketFrame) msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleHttpRequest</span><span class="params">(ChannelHandlerContext ctx,</span></span></span><br><span class="line"><span class="function"><span class="params">                                   FullHttpRequest req)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 如果HTTP解码失败，返回HTTP异常</span></span><br><span class="line">        <span class="keyword">if</span> (!req.decoderResult().isSuccess()</span><br><span class="line">                || (!<span class="string">"websocket"</span>.equals(req.headers().get(<span class="string">"Upgrade"</span>)))) &#123;</span><br><span class="line">            sendHttpResponse(ctx, req, <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1,</span><br><span class="line">                    BAD_REQUEST));</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Allow only GET methods.</span></span><br><span class="line">        <span class="keyword">if</span> (req.method() != GET) &#123;</span><br><span class="line">            sendHttpResponse(ctx, req, <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="string">"/favicon.ico"</span>.equals(req.uri()) || (<span class="string">"/"</span>.equals(req.uri()))) &#123;</span><br><span class="line">            sendHttpResponse(ctx, req, <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND));</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        QueryStringDecoder queryStringDecoder = <span class="keyword">new</span> QueryStringDecoder(req.uri());</span><br><span class="line">        Map&lt;String, List&lt;String&gt;&gt; parameters = queryStringDecoder.parameters();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (parameters.size() == <span class="number">0</span> || !parameters.containsKey(HTTP_REQUEST_STRING)) &#123;</span><br><span class="line">            System.err.printf(HTTP_REQUEST_STRING + <span class="string">"参数不可缺省"</span>);</span><br><span class="line">            sendHttpResponse(ctx, req, <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND));</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        String token = parameters.get(HTTP_REQUEST_STRING).get(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 用户唯一标识不存在返回,则新增一个频道 ChannelGroup</span></span><br><span class="line">        <span class="keyword">if</span> (!channelGroupMap.containsKey(token)) &#123;</span><br><span class="line">            channelGroupMap.put(token, <span class="keyword">new</span> DefaultChannelGroup(GlobalEventExecutor.INSTANCE));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 确定有唯一标识,才将客户端加入到频道中</span></span><br><span class="line">        channelGroupMap.get(token).add(ctx.channel());</span><br><span class="line">        Attribute&lt;String&gt; tokenAttr = ctx.channel().attr(TOKEN_CHANNEL_KEYS);</span><br><span class="line">        tokenAttr.setIfAbsent(token);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 构造握手响应返回</span></span><br><span class="line">        WebSocketServerHandshakerFactory wsFactory = <span class="keyword">new</span> WebSocketServerHandshakerFactory(</span><br><span class="line">                getWebSocketLocation(req), <span class="keyword">null</span>, <span class="keyword">false</span>);</span><br><span class="line">        handshaker = wsFactory.newHandshaker(req);</span><br><span class="line">        <span class="keyword">if</span> (handshaker == <span class="keyword">null</span>) &#123;</span><br><span class="line">            WebSocketServerHandshakerFactory</span><br><span class="line">                    .sendUnsupportedVersionResponse(ctx.channel());</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            handshaker.handshake(ctx.channel(), req);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleWebSocketFrame</span><span class="params">(ChannelHandlerContext ctx,</span></span></span><br><span class="line"><span class="function"><span class="params">                                      WebSocketFrame frame)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 判断是否是关闭链路的指令</span></span><br><span class="line">        <span class="keyword">if</span> (frame <span class="keyword">instanceof</span> CloseWebSocketFrame) &#123;</span><br><span class="line">            handshaker.close(ctx.channel(),</span><br><span class="line">                    (CloseWebSocketFrame) frame.retain());</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 判断是否是Ping消息</span></span><br><span class="line">        <span class="keyword">if</span> (frame <span class="keyword">instanceof</span> PingWebSocketFrame) &#123;</span><br><span class="line">            ctx.channel().write(</span><br><span class="line">                    <span class="keyword">new</span> PongWebSocketFrame(frame.content().retain()));</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 本例程仅支持文本消息，不支持二进制消息</span></span><br><span class="line">        <span class="keyword">if</span> (!(frame <span class="keyword">instanceof</span> TextWebSocketFrame)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException(String.format(</span><br><span class="line">                    <span class="string">"%s frame types not supported"</span>, frame.getClass().getName()));</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">        String request = ((TextWebSocketFrame) frame).text();</span><br><span class="line">        <span class="keyword">if</span> (logger.isLoggable(Level.FINE)) &#123;</span><br><span class="line">            logger.fine(String.format(<span class="string">"%s received %s"</span>, ctx.channel(), request));</span><br><span class="line">        &#125;</span><br><span class="line">        ctx.channel().write(<span class="keyword">new</span> TextWebSocketFrame(<span class="string">" 收到客户端请求："</span>+ request ));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sendHttpResponse</span><span class="params">(ChannelHandlerContext ctx,</span></span></span><br><span class="line"><span class="function"><span class="params">                                         FullHttpRequest req, FullHttpResponse res)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 返回应答给客户端</span></span><br><span class="line">        <span class="keyword">if</span> (res.status().code() != <span class="number">200</span>) &#123;</span><br><span class="line">            ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(),</span><br><span class="line">                    CharsetUtil.UTF_8);</span><br><span class="line">            res.content().writeBytes(buf);</span><br><span class="line">            buf.release();</span><br><span class="line">            setContentLength(res, res.content().readableBytes());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 如果是非Keep-Alive，关闭连接</span></span><br><span class="line">        ChannelFuture f = ctx.channel().writeAndFlush(res);</span><br><span class="line">        <span class="keyword">if</span> (!isKeepAlive(req) || res.status().code() != <span class="number">200</span>) &#123;</span><br><span class="line">            f.addListener(ChannelFutureListener.CLOSE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelReadComplete</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        ctx.flush();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span></span></span><br><span class="line"><span class="function">            <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        cause.printStackTrace();</span><br><span class="line">        close(ctx);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">(ChannelHandlerContext ctx)</span></span>&#123;</span><br><span class="line">        Attribute&lt;String&gt; tokenAttr = ctx.channel().attr(TOKEN_CHANNEL_KEYS);</span><br><span class="line">        String token = tokenAttr.get();</span><br><span class="line">        <span class="keyword">if</span> (token != <span class="keyword">null</span> &amp;&amp; channelGroupMap.containsKey(token)) &#123;<span class="comment">//从群组中移除</span></span><br><span class="line">            ChannelGroup channelGroup = channelGroupMap.get(token);</span><br><span class="line">            <span class="keyword">int</span> len = channelGroup.size();</span><br><span class="line">            <span class="keyword">if</span> (len &lt;= <span class="number">1</span>) &#123;<span class="comment">//群组就一个人直接移除群主</span></span><br><span class="line">                channelGroupMap.remove(token);</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                channelGroupMap.get(token).remove(ctx.channel());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handlerRemoved</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        close(ctx);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> String <span class="title">getWebSocketLocation</span><span class="params">(FullHttpRequest req)</span> </span>&#123;</span><br><span class="line">        String location = req.headers().get(HOST) + WEBSOCKET_PATH;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"ws://"</span> + location;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="测试与实战"><a href="#测试与实战" class="headerlink" title="测试与实战"></a>测试与实战</h3><p>1、采用html进行测试<br>源码如下：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">onsubmit</span>=<span class="string">"return false;"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span> Netty WebSocket 协议 <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h3</span>&gt;</span>客户端请求消息<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">textarea</span> <span class="attr">id</span>=<span class="string">"requestText"</span> <span class="attr">style</span>=<span class="string">"width:500px;height:200px;"</span>&gt;</span><span class="tag">&lt;/<span class="name">textarea</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"发送WebSocket请求消息"</span> <span class="attr">onclick</span>=<span class="string">"send(document.getElementById('requestText').value)"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h3</span>&gt;</span>服务端返回的应答消息<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">textarea</span> <span class="attr">id</span>=<span class="string">"responseText"</span> <span class="attr">style</span>=<span class="string">"width:600px;height:200px;"</span>&gt;</span><span class="tag">&lt;/<span class="name">textarea</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span></span><br><span class="line"><span class="actionscript">    <span class="function"><span class="keyword">function</span> <span class="title">guid</span><span class="params">()</span> </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">return</span> <span class="string">'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'</span>.replace(<span class="regexp">/[xy]/g</span>, <span class="function"><span class="keyword">function</span>(<span class="params">c</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">var</span> r = <span class="built_in">Math</span>.random()*<span class="number">16</span>|<span class="number">0</span>, v = c == <span class="string">'x'</span> ? r : (r&amp;<span class="number">0x3</span>|<span class="number">0x8</span>);</span></span><br><span class="line"><span class="actionscript">            <span class="keyword">return</span> v.toString(<span class="number">16</span>);</span></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="javascript">    <span class="built_in">window</span>.WebSocket = <span class="built_in">window</span>.WebSocket || <span class="built_in">window</span>.MozWebSocket;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (!<span class="built_in">window</span>.WebSocket)&#123;</span></span><br><span class="line"><span class="actionscript">        alert(<span class="string">"你的浏览器不支持websocket协议"</span>);</span></span><br><span class="line"><span class="actionscript">    &#125;<span class="keyword">else</span>&#123;</span></span><br><span class="line"><span class="actionscript">        <span class="keyword">var</span> socket = <span class="keyword">new</span> WebSocket(<span class="string">"ws://localhost:5052/ws_protocol?token="</span>+guid());</span></span><br><span class="line"><span class="actionscript">        socket.onmessage = <span class="function"><span class="keyword">function</span> <span class="params">(event)</span> </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">var</span> ta = <span class="built_in">document</span>.getElementById(<span class="string">'responseText'</span>);</span></span><br><span class="line"><span class="actionscript">            ta.value = ta.value + <span class="string">"\r\n"</span> + event.data</span></span><br><span class="line">        &#125;;</span><br><span class="line"><span class="actionscript">        socket.onopen = <span class="function"><span class="keyword">function</span> <span class="params">(event)</span> </span>&#123;</span></span><br><span class="line"><span class="actionscript">            alert(<span class="string">"websocket连接建立成功..."</span>);</span></span><br><span class="line">        &#125;;</span><br><span class="line"><span class="actionscript">        socket.onclose = <span class="function"><span class="keyword">function</span> <span class="params">(event)</span> </span>&#123;</span></span><br><span class="line"><span class="actionscript">            alert(<span class="string">"连接关闭"</span>);</span></span><br><span class="line">        &#125;;</span><br><span class="line"><span class="actionscript">        <span class="function"><span class="keyword">function</span> <span class="title">send</span><span class="params">(message)</span> </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">if</span> (!<span class="built_in">window</span>.WebSocket) &#123;</span></span><br><span class="line"><span class="actionscript">                <span class="keyword">return</span>;</span></span><br><span class="line">            &#125;</span><br><span class="line">            if (socket.readyState == WebSocket.OPEN) &#123;</span><br><span class="line">                socket.send(message);</span><br><span class="line">            &#125;</span><br><span class="line"><span class="actionscript">            <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="actionscript">                alert(<span class="string">"WebSocket not supported by this browser"</span>);</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;WebSocket介绍&quot;&gt;&lt;a href=&quot;#WebSocket介绍&quot; class=&quot;headerlink&quot; title=&quot;WebSocket介绍&quot;&gt;&lt;/a&gt;WebSocket介绍&lt;/h3&gt;&lt;p&gt;WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455，并由RFC7936补充规范。WebSocket API也被W3C定为标准。&lt;br&gt;WebSocket使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。在WebSocket API中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接，并进行双向数据传输。&lt;/p&gt;
&lt;h3 id=&quot;直接开始进入正题–SpringBoot-WebSocket-开始&quot;&gt;&lt;a href=&quot;#直接开始进入正题–SpringBoot-WebSocket-开始&quot; class=&quot;headerlink&quot; title=&quot;直接开始进入正题–SpringBoot WebSocket 开始&quot;&gt;&lt;/a&gt;直接开始进入正题–SpringBoot WebSocket 开始&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;1、搭建环境&lt;/strong&gt;&lt;br&gt;你还在手动搭建项目码？都9102年了还在手动，我们早都全自动了。不会的请戳这里&lt;a href=&quot;https://start.spring.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://start.spring.io/&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="netty" scheme="http://www.180716.xyz/categories/netty/"/>
    
    
  </entry>
  
  <entry>
    <title>Linux执行Shell提示No such file or directory</title>
    <link href="http://www.180716.xyz/debian/debian/shell_no_such_file.shtml"/>
    <id>http://www.180716.xyz/debian/debian/shell_no_such_file.shtml</id>
    <published>2019-11-14T08:05:18.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<p>line 1: ﻿#!/bin/sh: No such file or directory<br>造成这样的原因,编码格式问题UTF-8 Unicode (with BOM)问题,解决办法就是将文件中 BOM信息删除掉。<br>Use dos2unix (or sed, tr, awk, perl, python…) to fix your script if this is the issue.Here is one that will remove both of a BOM and tailing CRs:</p><p>查看shell脚本头部信息发现</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">root@debian:/<span class="comment"># head -1 /data/deploy/deploy.sh | od -c</span></span><br><span class="line">0000000 357 273 277   <span class="comment">#   !   /   b   i   n   /   s   h  \n</span></span><br><span class="line">0000015</span><br></pre></td></tr></table></figure><p>发现 #!/bin 前面有数字 357 273 277  这个应该就是文件BOM信息,删掉它就能解决问题了。</p><p>1、方法一</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">'1s/^.*#//;s/\r$//'</span> /data/deploy/deploy.sh</span><br></pre></td></tr></table></figure><a id="more"></a><p>2、方法二<br>使用dos2unix 命令进行dos脚本转unix</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@debian:/<span class="comment"># dos2unix /data/deploy/deploy.sh</span></span><br><span class="line">Command <span class="string">'dos2unix'</span> not found, but can be installed with:</span><br></pre></td></tr></table></figure><p>使用 <strong>apt-get install dos2unix</strong> 进行安装 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@debian:/<span class="comment"># dos2unix /data/deploy/deploy.sh </span></span><br><span class="line">dos2unix: converting file /data/deploy/deploy.sh to Unix format...</span><br></pre></td></tr></table></figure><p>3、测试</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">root@debian:/<span class="comment"># head -1 /data/deploy/deploy.sh  | od -c</span></span><br><span class="line">0000000   <span class="comment">#   !   /   b   i   n   /   s   h  \n</span></span><br><span class="line">0000012</span><br></pre></td></tr></table></figure><p>正常了执行shell再也不会提示line 1: ﻿#!/bin/sh: No such file or directory</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;line 1: ﻿#!/bin/sh: No such file or directory&lt;br&gt;造成这样的原因,编码格式问题UTF-8 Unicode (with BOM)问题,解决办法就是将文件中 BOM信息删除掉。&lt;br&gt;Use dos2unix (or sed, tr, awk, perl, python…) to fix your script if this is the issue.Here is one that will remove both of a BOM and tailing CRs:&lt;/p&gt;
&lt;p&gt;查看shell脚本头部信息发现&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;root@debian:/&lt;span class=&quot;comment&quot;&gt;# head -1 /data/deploy/deploy.sh | od -c&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;0000000 357 273 277   &lt;span class=&quot;comment&quot;&gt;#   !   /   b   i   n   /   s   h  \n&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;0000015&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;发现 #!/bin 前面有数字 357 273 277  这个应该就是文件BOM信息,删掉它就能解决问题了。&lt;/p&gt;
&lt;p&gt;1、方法一&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;sed -i &lt;span class=&quot;string&quot;&gt;&#39;1s/^.*#//;s/\r$//&#39;&lt;/span&gt; /data/deploy/deploy.sh&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="debian" scheme="http://www.180716.xyz/categories/debian/"/>
    
    
  </entry>
  
  <entry>
    <title>logrotate日志管理工具</title>
    <link href="http://www.180716.xyz/debian/debian/logrotate.shtml"/>
    <id>http://www.180716.xyz/debian/debian/logrotate.shtml</id>
    <published>2019-11-14T04:50:18.000Z</published>
    <updated>2022-10-25T00:53:09.000Z</updated>
    
    <content type="html"><![CDATA[<p>一般来说，日志是任何故障排除过程中非常重要的一部分，但这些日志会随着时间增长。在这种情况下，我们需要手动执行日志清理以回收空间，这是一件繁琐的管理任务。为了解决这个问题，我们可以在 Linux 中配置 logrotate 程序，它可以自动执行日志文件的轮换、压缩、删除和用邮件发出。<br>我们可以配置 logrotate 程序，以便每个日志文件可以在每天、每周、每月或当它变得太大时处理。</p><p><strong>1、配置实例</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">/usr/<span class="built_in">local</span>/nginx/logs/*.<span class="built_in">log</span> &#123;</span><br><span class="line">daily</span><br><span class="line">rotate 7</span><br><span class="line">missingok</span><br><span class="line">notifempty</span><br><span class="line">dateext</span><br><span class="line">sharedscripts</span><br><span class="line">postrotate</span><br><span class="line">    <span class="keyword">if</span> [ -f /usr/<span class="built_in">local</span>/nginx/logs/nginx.pid ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">kill</span> -USR1 `cat /usr/<span class="built_in">local</span>/nginx/logs/nginx.pid`</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">endscript</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><a id="more"></a><p><strong>2、配置选项说明</strong></p><table><thead><tr><th align="left">参数</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="left">compress</td><td align="left">通过gzip 压缩转储以后的日志</td></tr><tr><td align="left">nocompress</td><td align="left">不做gzip压缩处理</td></tr><tr><td align="left">copytruncate</td><td align="left">用于还在打开中的日志文件，把当前日志备份并截断；是先拷贝再清空的方式，拷贝和清空之间有一个时间差，可能会丢失部分日志数据。</td></tr><tr><td align="left">nocopytruncate</td><td align="left">备份日志文件不过不截断</td></tr><tr><td align="left">create mode owner group</td><td align="left">轮转时指定创建新文件的属性，如create 0777 nobody nobody</td></tr><tr><td align="left">nocreate</td><td align="left">不建立新的日志文件</td></tr><tr><td align="left">delaycompress</td><td align="left">和compress 一起使用时，转储的日志文件到下一次转储时才压缩</td></tr><tr><td align="left">nodelaycompress</td><td align="left">覆盖 delaycompress 选项，转储同时压缩。</td></tr><tr><td align="left">missingok</td><td align="left">如果日志丢失，不报错继续滚动下一个日志</td></tr><tr><td align="left">errors address</td><td align="left">专储时的错误信息发送到指定的Email 地址</td></tr><tr><td align="left">ifempty</td><td align="left">即使日志文件为空文件也做轮转，这个是logrotate的缺省选项。</td></tr><tr><td align="left">notifempty</td><td align="left">当日志文件为空时，不进行轮转</td></tr><tr><td align="left">mail address</td><td align="left">把转储的日志文件发送到指定的E-mail 地址</td></tr><tr><td align="left">nomail</td><td align="left">转储时不发送日志文件</td></tr><tr><td align="left">olddir directory</td><td align="left">转储后的日志文件放入指定的目录，必须和当前日志文件在同一个文件系统</td></tr><tr><td align="left">noolddir</td><td align="left">转储后的日志文件和当前日志文件放在同一个目录下</td></tr><tr><td align="left">sharedscripts</td><td align="left">运行postrotate脚本，作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个，那么每个日志轮转后都会执行一次脚本</td></tr><tr><td align="left">prerotate</td><td align="left">在logrotate转储之前需要执行的指令，例如修改文件的属性等动作；必须独立成行</td></tr><tr><td align="left">postrotate</td><td align="left">在logrotate转储之后需要执行的指令，例如重新启动 (kill -HUP) 某个服务！必须独立成行</td></tr><tr><td align="left">daily</td><td align="left">指定转储周期为每天</td></tr><tr><td align="left">weekly</td><td align="left">指定转储周期为每周</td></tr><tr><td align="left">monthly</td><td align="left">指定转储周期为每月</td></tr><tr><td align="left">rotate count</td><td align="left">指定日志文件删除之前转储的次数，0 指没有备份，5 指保留5 个备份</td></tr><tr><td align="left">dateext</td><td align="left">使用当期日期作为命名格式</td></tr><tr><td align="left">dateformat .%s</td><td align="left">配合dateext使用，紧跟在下一行出现，定义文件切割后的文件名，必须配合dateext使用，只支持 %Y %m %d %s 这四个参数</td></tr><tr><td align="left">size(或minsize)</td><td align="left">log-size当日志文件到达指定的大小时才转储，log-size能指定bytes(缺省)及KB (sizek)或MB(sizem).    当日志文件 &gt;= log-size 的时候就转储。     以下为合法格式：    （其他格式的单位大小写没有试过）size = 5 或 size 5 （&gt;= 5 个字节就转储）    size = 100k 或 size 100k size = 100M 或 size 100M</td></tr></tbody></table><p><strong>3、命令参数说明</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># logrotate --help</span></span><br><span class="line">Usage: logrotate [OPTION...] &lt;configfile&gt;</span><br><span class="line">  -d, --debug 调试模式，输出调试结果，并不执行。隐式-v参数</span><br><span class="line">  -f, --force 强制模式，对所有相关文件进行rotate</span><br><span class="line">  -m, --mail=<span class="built_in">command</span>        发送邮件 (instead of `/bin/mail<span class="string">')</span></span><br><span class="line"><span class="string">  -s, --state=statefile     状态文件，对于运行在不同用户情况下有用</span></span><br><span class="line"><span class="string">  -v, --verbose             显示debug信息</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;一般来说，日志是任何故障排除过程中非常重要的一部分，但这些日志会随着时间增长。在这种情况下，我们需要手动执行日志清理以回收空间，这是一件繁琐的管理任务。为了解决这个问题，我们可以在 Linux 中配置 logrotate 程序，它可以自动执行日志文件的轮换、压缩、删除和用邮件发出。&lt;br&gt;我们可以配置 logrotate 程序，以便每个日志文件可以在每天、每周、每月或当它变得太大时处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1、配置实例&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;13&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;/usr/&lt;span class=&quot;built_in&quot;&gt;local&lt;/span&gt;/nginx/logs/*.&lt;span class=&quot;built_in&quot;&gt;log&lt;/span&gt; &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	daily&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	rotate 7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	missingok&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	notifempty&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	dateext&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	sharedscripts&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	postrotate&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; [ -f /usr/&lt;span class=&quot;built_in&quot;&gt;local&lt;/span&gt;/nginx/logs/nginx.pid ]; &lt;span class=&quot;keyword&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	        &lt;span class=&quot;built_in&quot;&gt;kill&lt;/span&gt; -USR1 `cat /usr/&lt;span class=&quot;built_in&quot;&gt;local&lt;/span&gt;/nginx/logs/nginx.pid`&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	    &lt;span class=&quot;keyword&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;	endscript&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="debian" scheme="http://www.180716.xyz/categories/debian/"/>
    
    
  </entry>
  
  <entry>
    <title>Java部署之SpringBoot项目</title>
    <link href="http://www.180716.xyz/java/java/java_deploy.shtml"/>
    <id>http://www.180716.xyz/java/java/java_deploy.shtml</id>
    <published>2019-11-12T10:05:41.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：功能介绍相关命令介绍"><a href="#第一部分：功能介绍相关命令介绍" class="headerlink" title="第一部分：功能介绍相关命令介绍"></a>第一部分：功能介绍相关命令介绍</h2><p>功能描述:Windows开发环境部署生成Liunx环境,上传文件至特定目录,执行相关Shell命令。<br>plink及pscp工具均为Putty工具包产品分别用于执行Shell命令及上传文件使用</p><figure class="highlight plain"><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">https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html</span><br><span class="line">下载.tar.gz: putty-0.73.tar.gz</span><br></pre></td></tr></table></figure><h2 id="第二部分：相关Shell文件"><a href="#第二部分：相关Shell文件" class="headerlink" title="第二部分：相关Shell文件"></a>第二部分：相关Shell文件</h2><p><strong>Windows上传Linux服务器并执行Shell的Dos脚本</strong></p><a id="more"></a><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">@<span class="built_in">echo</span> off</span><br><span class="line">REM 声明采用UTF-8编码</span><br><span class="line">chcp 65001</span><br><span class="line"><span class="built_in">set</span> project_path=Jar文件所在目录</span><br><span class="line"><span class="built_in">set</span> local_file=上传Jar文件名称,如果多个使用空格隔开</span><br><span class="line"><span class="built_in">set</span> deploy-shell=Linux服务器上执行部署的Shell</span><br><span class="line"> </span><br><span class="line"><span class="built_in">set</span> server_user=Linux用户名</span><br><span class="line"><span class="built_in">set</span> server_passwd=Linux密码</span><br><span class="line"><span class="built_in">set</span> server_ip=Linux服务器IP地址</span><br><span class="line"> </span><br><span class="line"><span class="built_in">echo</span> ---------------------------------------------- upload file to server </span><br><span class="line">call pscp.exe -l %server_user% -pw %server_passwd% -r %local_file% %server_ip%:%project_path%</span><br><span class="line"><span class="built_in">echo</span> -----------upload success--------------------- </span><br><span class="line"><span class="built_in">echo</span> ---------------------------------------------- execute %deploy-shell%</span><br><span class="line">call plink.exe -pw %server_passwd%  %server_user%@%server_ip% <span class="string">"%deploy-shell%"</span></span><br><span class="line"><span class="built_in">echo</span> -----------execute success--------------------- </span><br><span class="line">pause</span><br></pre></td></tr></table></figure><p><strong>Linux服务器部署备份处理日志Shell</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"></span><br><span class="line">JAVA_HOME=/usr/java/jdk1.8.0_202;</span><br><span class="line">PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$PATH</span>;</span><br><span class="line"></span><br><span class="line">spring_prod=<span class="string">"prod"</span>; <span class="comment">#生产环境</span></span><br><span class="line">app_jar=<span class="string">""</span>; <span class="comment">#运行jar或者war</span></span><br><span class="line">jar_bak_dir=<span class="string">""</span>; <span class="comment">#jar或者war备份地址</span></span><br><span class="line">deploy_dir=<span class="string">""</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="built_in">export</span> JAVA_HOME;</span><br><span class="line"><span class="built_in">export</span> PATH;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 第二部杀掉进程、部署、生成备份日志文件</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">kill_java_pid</span></span>()&#123;</span><br><span class="line">  jar_path=<span class="variable">$1</span>; <span class="comment">#java部署目录</span></span><br><span class="line">  <span class="comment"># 找到java的进程id</span></span><br><span class="line">  java_pid=$(ps -ef | grep <span class="string">"<span class="variable">$app_jar</span>"</span> | grep -v grep | awk <span class="string">'&#123;print $2&#125;'</span> |tr -s <span class="string">'\n'</span> <span class="string">' '</span>)</span><br><span class="line">  <span class="keyword">if</span> [ <span class="string">"<span class="variable">$java_pid</span>"</span> ];<span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"发现java进程pid:<span class="variable">$java_pid</span>"</span>; </span><br><span class="line">    <span class="comment"># 杀掉tomcat进程</span></span><br><span class="line">    <span class="keyword">if</span></span><br><span class="line">      <span class="built_in">kill</span> -9 <span class="variable">$java_pid</span>;</span><br><span class="line">    <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">echo</span> <span class="string">"杀掉java进程pid:<span class="variable">$java_pid</span>成功..."</span>;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">     <span class="built_in">echo</span> <span class="string">"杀掉java进程失败..."</span>;</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"java进程不存在或者已经被杀死..."</span>;</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#将jar或者war生成的catalina.out 添加系统 logrotate</span></span><br><span class="line"><span class="function"><span class="title">bak_log_config</span></span>()&#123;</span><br><span class="line">  <span class="keyword">if</span> [ -d <span class="string">"/etc/logrotate.d/"</span> ];<span class="keyword">then</span></span><br><span class="line">  <span class="keyword">if</span> [ -f <span class="string">"/etc/logrotate.d/customize"</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"logrotate 配置文件已经存在... 终止"</span>;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">      <span class="comment"># logrotate catalina.out</span></span><br><span class="line">    cat &gt; /etc/logrotate.d/customize &lt;&lt; EOF</span><br><span class="line"><span class="variable">$&#123;jar_bak_dir&#125;</span>/catalina.out &#123;</span><br><span class="line">  su root list</span><br><span class="line">  daily</span><br><span class="line">  rotate 5</span><br><span class="line">  missingok</span><br><span class="line">  dateext</span><br><span class="line">  compress</span><br><span class="line">  notifempty</span><br><span class="line">  copytruncate</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">"没有发现logrotate... 终止"</span>;</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">deploy_java</span></span>()&#123;</span><br><span class="line">  <span class="built_in">cd</span> <span class="string">"<span class="variable">$deploy_dir</span>"</span>; <span class="comment">#跳转至准备部署目录</span></span><br><span class="line">  <span class="comment"># -f 参数判断 app_jar 是否存在</span></span><br><span class="line">  <span class="keyword">if</span> [ -f <span class="string">"<span class="variable">$app_jar</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">    kill_java_pid <span class="string">"<span class="variable">$jar_bak_dir</span>"</span>;</span><br><span class="line">    cp <span class="string">"<span class="variable">$jar_bak_dir</span>/<span class="variable">$app_jar</span>"</span> <span class="string">"<span class="variable">$jar_bak_dir</span>/<span class="variable">$app_jar</span>.`date '+%Y%m%d%H%M%S'`"</span>; <span class="comment">#备份原有代码</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"备份<span class="variable">$app_jar</span>成功..."</span>;</span><br><span class="line">    <span class="keyword">if</span> [ <span class="string">"<span class="variable">$deploy_dir</span>"</span> != <span class="string">"<span class="variable">$jar_bak_dir</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">      cp <span class="string">"<span class="variable">$app_jar</span>"</span> <span class="string">"<span class="variable">$jar_bak_dir</span>"</span>;</span><br><span class="line">    <span class="keyword">fi</span>    </span><br><span class="line">    nohup java -Dspring.profiles.active=<span class="variable">$spring_prod</span> -Xms128m -Xmx128m -Xss512K -XX:PermSize=128m -XX:MaxPermSize=256m -jar <span class="string">"<span class="variable">$jar_bak_dir</span>/<span class="variable">$app_jar</span>"</span> &gt;&gt; <span class="string">"<span class="variable">$jar_bak_dir</span>/catalina.out"</span> 2&gt;&amp;1 &amp;</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"部署<span class="variable">$app_jar</span>成功..."</span>;</span><br><span class="line">    bak_log_config;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"没有找到<span class="variable">$app_jar</span>请先上传文件..."</span>;</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">deploy_java; <span class="comment">#部署</span></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;功能描述:Windows开发环境部署生成Liunx环境,上传文件至特定目录,执行相关Shell命令。&lt;br&gt;plink及pscp工具均为Putty工具包产品分别用于执行Shell命令及上传文件使用&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;# 下载地址如下：&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;下载.tar.gz: putty-0.73.tar.gz&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;h2 id=&quot;第二部分：相关Shell文件&quot;&gt;&lt;a href=&quot;#第二部分：相关Shell文件&quot; class=&quot;headerlink&quot; title=&quot;第二部分：相关Shell文件&quot;&gt;&lt;/a&gt;第二部分：相关Shell文件&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Windows上传Linux服务器并执行Shell的Dos脚本&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://www.180716.xyz/categories/java/"/>
    
    
  </entry>
  
  <entry>
    <title>TortoiseSVN手动清除访问记录</title>
    <link href="http://www.180716.xyz/svn/svn/svn_clear_url.shtml"/>
    <id>http://www.180716.xyz/svn/svn/svn_clear_url.shtml</id>
    <published>2019-11-11T08:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="方案一：清除所有记录"><a href="#方案一：清除所有记录" class="headerlink" title="方案一：清除所有记录"></a>方案一：清除所有记录</h2><figure class="highlight plain"><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">右键&gt;TortoiseSVN&gt;Saved Data&gt;URL history</span><br><span class="line">点击Clear按钮，一键清除所有历史浏览URL</span><br></pre></td></tr></table></figure><p><img src="/upload/svn/tortoisesvn_tool_clear.png" alt="alt text" title="工具清理所有历史URL"></p><a id="more"></a><h2 id="方案二：可清除某一条URL记录"><a href="#方案二：可清除某一条URL记录" class="headerlink" title="方案二：可清除某一条URL记录"></a>方案二：可清除某一条URL记录</h2><figure class="highlight plain"><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">修改注册表 WIn+R 输入 regedit</span><br><span class="line">HKEY_CURRENT_USER\Software\TortoiseSVN\History\repoURLS</span><br></pre></td></tr></table></figure><p><img src="/upload/svn/regedit_delete_url.png" alt="alt text" title="注册表删除历史URL"></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">注意：如果你删除url0，需要保证url后面数字连续</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;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;在文件夹空白处：&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;右键&amp;gt;TortoiseSVN&amp;gt;Saved Data&amp;gt;URL history&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;点击Clear按钮，一键清除所有历史浏览URL&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/upload/svn/tortoisesvn_tool_clear.png&quot; alt=&quot;alt text&quot; title=&quot;工具清理所有历史URL&quot;&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="svn" scheme="http://www.180716.xyz/categories/svn/"/>
    
    
  </entry>
  
  <entry>
    <title>Linux安装Solr8.3及应用</title>
    <link href="http://www.180716.xyz/solr/solr/solr_install.shtml"/>
    <id>http://www.180716.xyz/solr/solr/solr_install.shtml</id>
    <published>2019-11-10T14:50:18.000Z</published>
    <updated>2022-10-25T00:53:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一部分：安装Solr配置"><a href="#第一部分：安装Solr配置" class="headerlink" title="第一部分：安装Solr配置"></a>第一部分：安装Solr配置</h2><p>基于Lucene的Java搜索引擎服务器<br>Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成，以及富文本（如Word、PDF）的处理。Solr是高度可扩展的，并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎，Solr4 还增加了NoSQL支持。</p><p><strong>下载Solr</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#官方地址: http://lucene.apache.org/solr/downloads.html</span></span><br><span class="line">wget https://www.apache.org/dyn/closer.lua/lucene/solr/8.3.0/solr-8.3.0.tgz</span><br><span class="line">tar -zxvf solr-8.3.0.tgz</span><br><span class="line"><span class="built_in">cd</span> solr-8.3.0/bin</span><br></pre></td></tr></table></figure><p><strong>启动测试</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./solr start -force</span><br></pre></td></tr></table></figure><a id="more"></a><p><strong>Solr相关命令</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><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">./solr start –p 端口号   #单机版启动solr服务</span><br><span class="line">./solr restart –p 端口号 #重启solr服务</span><br><span class="line">./solr stop –p 端口号    #关闭solr服务</span><br><span class="line">./solr stop -all         #关闭所有solr服务</span><br><span class="line">./solr status            #查看solr状态</span><br><span class="line">./solr create –c name    #创建一个core实例(core概念后面介绍)</span><br></pre></td></tr></table></figure><h2 id="第二部分：配置Solr支持中文词库解析"><a href="#第二部分：配置Solr支持中文词库解析" class="headerlink" title="第二部分：配置Solr支持中文词库解析"></a>第二部分：配置Solr支持中文词库解析</h2><p><strong>中文词库下载配置</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 词库下载地址</span><br><span class="line">https://github.com/magese/ik-analyzer-solr</span><br></pre></td></tr></table></figure><p><img src="/upload/solr/solr_directions.png" alt="alt text" title="Solr中文词库使用说明"></p><p>Maven仓库地址</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><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">&lt;!-- Maven仓库地址 --&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;com.github.magese&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;ik-analyzer&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;8.2.0&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure><p>solr-8.3.0/server/solr/newCore/conf/managed-schema文件里面添加</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- ik分词器 --&gt;</span><br><span class="line">&lt;fieldType name=&quot;text_ik&quot; class=&quot;solr.TextField&quot;&gt;</span><br><span class="line">  &lt;analyzer type=&quot;index&quot;&gt;</span><br><span class="line">      &lt;tokenizer class=&quot;org.wltea.analyzer.lucene.IKTokenizerFactory&quot; useSmart=&quot;false&quot; conf=&quot;ik.conf&quot;/&gt;</span><br><span class="line">      &lt;filter class=&quot;solr.LowerCaseFilterFactory&quot;/&gt;</span><br><span class="line">  &lt;/analyzer&gt;</span><br><span class="line">  &lt;analyzer type=&quot;query&quot;&gt;</span><br><span class="line">      &lt;tokenizer class=&quot;org.wltea.analyzer.lucene.IKTokenizerFactory&quot; useSmart=&quot;true&quot; conf=&quot;ik.conf&quot;/&gt;</span><br><span class="line">      &lt;filter class=&quot;solr.LowerCaseFilterFactory&quot;/&gt;</span><br><span class="line">  &lt;/analyzer&gt;</span><br><span class="line">&lt;/fieldType&gt;</span><br></pre></td></tr></table></figure><p><strong>官方测试API地址</strong></p><figure class="highlight plain"><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">#官方测试API地址：</span><br><span class="line">https://lucene.apache.org/solr/guide/8_1/schema-api.html#modify-the-schema</span><br></pre></td></tr></table></figure><h2 id="第三部分：添加core并使用"><a href="#第三部分：添加core并使用" class="headerlink" title="第三部分：添加core并使用"></a>第三部分：添加core并使用</h2><p><strong>创建核心 Add Core</strong></p><p><img src="/upload/solr/solr_add_core.png" alt="alt text" title="创建核心Add Core"></p><p><strong>说明:Add Core之前必须使用命令solr-8.3.0/server/solr目录创建newCore,否则会报错</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> solr-8.3.0/server/solr</span><br><span class="line">mkdir newCore</span><br><span class="line">cp -R solr-8.3.0/server/solr/configsets/sample_techproducts_configs/conf /newCore</span><br></pre></td></tr></table></figure><p><img src="/upload/solr/solr_core_analysis.png" alt="alt text" title="Core测试分析"></p><h2 id="第四部分：清除Core搜索数据"><a href="#第四部分：清除Core搜索数据" class="headerlink" title="第四部分：清除Core搜索数据"></a>第四部分：清除Core搜索数据</h2><p><strong>清除Solr中数据</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;delete&gt;&lt;query&gt;*:*&lt;/query&gt;&lt;/delete&gt;</span><br><span class="line">&lt;commit/&gt;</span><br></pre></td></tr></table></figure><p><img src="/upload/solr/solr_clear_data.png" alt="alt text" title="清除Core中数据"></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;第一部分：安装Solr配置&quot;&gt;&lt;a href=&quot;#第一部分：安装Solr配置&quot; class=&quot;headerlink&quot; title=&quot;第一部分：安装Solr配置&quot;&gt;&lt;/a&gt;第一部分：安装Solr配置&lt;/h2&gt;&lt;p&gt;基于Lucene的Java搜索引擎服务器&lt;br&gt;Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成，以及富文本（如Word、PDF）的处理。Solr是高度可扩展的，并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎，Solr4 还增加了NoSQL支持。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;下载Solr&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;#官方地址: http://lucene.apache.org/solr/downloads.html&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;wget https://www.apache.org/dyn/closer.lua/lucene/solr/8.3.0/solr-8.3.0.tgz&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;tar -zxvf solr-8.3.0.tgz&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;cd&lt;/span&gt; solr-8.3.0/bin&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;启动测试&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;./solr start -force&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
      <category term="solr" scheme="http://www.180716.xyz/categories/solr/"/>
    
    
  </entry>
  
</feed>
