<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>一切随缘的技术博客</title>
  <icon>https://www.gravatar.com/avatar/d843950e6addab9cb2ebd3eee5c6cef7</icon>
  <subtitle>日拱一卒无有尽、功不唐捐终入海</subtitle>
  <link href="http://next.skyheng.com/atom.xml" rel="self"/>
  
  <link href="http://next.skyheng.com/"/>
  <updated>2025-11-30T14:41:25.910Z</updated>
  <id>http://next.skyheng.com/</id>
  
  <author>
    <name>一切随缘</name>
    <email>1225948009@qq.com</email>
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>开源软件镜像站汇总</title>
    <link href="http://next.skyheng.com/post/52244.html"/>
    <id>http://next.skyheng.com/post/52244.html</id>
    <published>2023-11-24T09:49:13.000Z</published>
    <updated>2025-11-30T14:41:25.910Z</updated>
    
    <content type="html"><![CDATA[<p>开源软件镜像站汇总</p><span id="more"></span><p><a href="https://nic.hibu.edu.cn/?m=home&c=View&a=index&aid=113">开源软件镜像站汇总</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;开源软件镜像站汇总&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>RocketMQ官方运维管理命令mqadmin使用手册 讲解-实操</title>
    <link href="http://next.skyheng.com/post/22144.html"/>
    <id>http://next.skyheng.com/post/22144.html</id>
    <published>2023-03-01T13:52:33.000Z</published>
    <updated>2025-11-30T14:41:25.911Z</updated>
    
    <content type="html"><![CDATA[<p>这个地方是写描述的地方</p><span id="more"></span><p><em>内容有点多，左侧有菜单</em></p><p> 进入<a href="https://so.csdn.net/so/search?q=RocketMQ&spm=1001.2101.3001.7020">RocketMQ</a>的bin目录：${PACKAGE}&#x2F;bin，使用命令<strong>bash mqadmin</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]# sh mqadmin</span><br><span class="line">The most commonly used mqadmin commands are:</span><br><span class="line">   updateTopic          Update or create topic</span><br><span class="line">   deleteTopic          Delete topic from broker and NameServer.</span><br><span class="line">   updateSubGroup       Update or create subscription group</span><br><span class="line">   deleteSubGroup       Delete subscription group from broker.</span><br><span class="line">   updateBrokerConfig   Update broker<span class="string">&#x27;s config</span></span><br><span class="line"><span class="string">   updateTopicPerm      Update topic perm</span></span><br><span class="line"><span class="string">   topicRoute           Examine topic route info</span></span><br><span class="line"><span class="string">   topicStatus          Examine topic Status info</span></span><br><span class="line"><span class="string">   topicClusterList     get cluster info for topic</span></span><br><span class="line"><span class="string">   brokerStatus         Fetch broker runtime status data</span></span><br><span class="line"><span class="string">   queryMsgById         Query Message by Id</span></span><br><span class="line"><span class="string">   queryMsgByKey        Query Message by Key</span></span><br><span class="line"><span class="string">   queryMsgByUniqueKey  Query Message by Unique key</span></span><br><span class="line"><span class="string">   queryMsgByOffset     Query Message by offset</span></span><br><span class="line"><span class="string">   printMsg             Print Message Detail</span></span><br><span class="line"><span class="string">   printMsgByQueue      Print Message Detail</span></span><br><span class="line"><span class="string">   sendMsgStatus        send msg to broker.</span></span><br><span class="line"><span class="string">   brokerConsumeStats   Fetch broker consume stats data</span></span><br><span class="line"><span class="string">   producerConnection   Query producer&#x27;</span>s socket connection and client version</span><br><span class="line">   consumerConnection   Query consumer<span class="string">&#x27;s socket connection, client version and subscription</span></span><br><span class="line"><span class="string">   consumerProgress     Query consumers&#x27;</span>s progress, speed</span><br><span class="line">   consumerStatus       Query consumer<span class="string">&#x27;s internal data structure</span></span><br><span class="line"><span class="string">   cloneGroupOffset     clone offset from other group.</span></span><br><span class="line"><span class="string">   clusterList          List all of clusters</span></span><br><span class="line"><span class="string">   topicList            Fetch all topic list from name server</span></span><br><span class="line"><span class="string">   updateKvConfig       Create or update KV config.</span></span><br><span class="line"><span class="string">   deleteKvConfig       Delete KV config.</span></span><br><span class="line"><span class="string">   wipeWritePerm        Wipe write perm of broker in all name server</span></span><br><span class="line"><span class="string">   resetOffsetByTime    Reset consumer offset by timestamp(without client restart).</span></span><br><span class="line"><span class="string">   updateOrderConf      Create or update or delete order conf</span></span><br><span class="line"><span class="string">   cleanExpiredCQ       Clean expired ConsumeQueue on broker.</span></span><br><span class="line"><span class="string">   cleanUnusedTopic     Clean unused topic on broker.</span></span><br><span class="line"><span class="string">   startMonitoring      Start Monitoring</span></span><br><span class="line"><span class="string">   statsAll             Topic and Consumer tps stats</span></span><br><span class="line"><span class="string">   allocateMQ           Allocate MQ</span></span><br><span class="line"><span class="string">   checkMsgSendRT       check message send response time</span></span><br><span class="line"><span class="string">   clusterRT            List All clusters Message Send RT</span></span><br><span class="line"><span class="string">   getNamesrvConfig     Get configs of name server.</span></span><br><span class="line"><span class="string">   updateNamesrvConfig  Update configs of name server.</span></span><br><span class="line"><span class="string">   getBrokerConfig      Get broker config by cluster or special broker!</span></span><br><span class="line"><span class="string">   queryCq              Query cq command.</span></span><br><span class="line"><span class="string">   sendMessage          Send a message</span></span><br><span class="line"><span class="string">   consumeMessage       Consume message</span></span><br><span class="line"><span class="string">   updateAclConfig      Update acl config yaml file in broker</span></span><br><span class="line"><span class="string">   deleteAccessConfig   Delete Acl Config Account in broker</span></span><br><span class="line"><span class="string">   clusterAclConfigVersion List all of acl config version information in cluster</span></span><br><span class="line"><span class="string">   updateGlobalWhiteAddr Update global white address for acl Config File in broker</span></span><br><span class="line"><span class="string">   getAccessConfigSubCommand List all of acl config information in cluster</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">See &#x27;</span>mqadmin <span class="built_in">help</span> &lt;<span class="built_in">command</span>&gt;<span class="string">&#x27; for more information on a specific command.</span></span><br></pre></td></tr></table></figure><p> 其中列出了最常用的命令，并附有简短说明。要获取每个命令的详细手册，使用命令**：bash mqadmin help <strong>。例如，命令</strong>bash mqadmin help clusterList**将显示以下帮助文本：</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">[root@localhost-001 bin]# bash mqadmin <span class="built_in">help</span> clusterList </span><br><span class="line">usage: mqadmin clusterList [-h] [-i &lt;arg&gt;] [-m] [-n &lt;arg&gt;]</span><br><span class="line"> -h,--<span class="built_in">help</span>                Print <span class="built_in">help</span></span><br><span class="line"> -i,--interval &lt;arg&gt;      specify intervals numbers, it is <span class="keyword">in</span> seconds</span><br><span class="line"> -m,--moreStats           Print more stats</span><br><span class="line"> -n,--namesrvAddr &lt;arg&gt;   Name server address list, eg: 192.168.0.1:9876;192.168.0.2:9876</span><br><span class="line">[root@localhost-001 bin]# </span><br></pre></td></tr></table></figure><h2 id="Topic相关"><a href="#Topic相关" class="headerlink" title="Topic相关"></a>Topic相关</h2><h3 id="updateTopic"><a href="#updateTopic" class="headerlink" title="updateTopic"></a>updateTopic</h3><p><strong>作用</strong>：修改或创建一个Topic</p><p><strong>命令</strong>：mqadmin updateTopic -b | -c [-h] [-n ] [-o ] [-p ] [-r ] [-s ] -t [-u ] [-w ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-b,–brokerAddr</td><td>broker 地址，表示topic 建在该broker</td><td>如果-c为空，则必填</td></tr><tr><td>-c,–clusterName</td><td>cluster 名称，表示topic 建在该集群</td><td>如果-b为空，则必填</td></tr><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>name server地址列表</td><td>以分号分割，例如：192.168.0.1:9876;192.168.0.2:9876</td></tr><tr><td>-o,–order</td><td>设置topic是否为有序的</td><td>取值：true、false(默认)</td></tr><tr><td>-p,–perm</td><td>设置topic的权限</td><td>取值：2、4、6；含义：2-W、4-R、6-RW(默认)</td></tr><tr><td>-r,–readQueueNums</td><td>设置可读队列数</td><td>默认为8</td></tr><tr><td>-s,–hasUnitSub</td><td>设置是否有unit sub</td><td>取值：true、false</td></tr><tr><td>-t,–topic</td><td>设置topic名称</td><td>名称只能使用字符 ^[a-zA-Z0-9_-]+$</td></tr><tr><td>-u,–unit</td><td>设置是否为unit topic</td><td>取值：true、false</td></tr><tr><td>-w,–writeQueueNums</td><td>设置可写队列数</td><td>默认为8</td></tr></tbody></table><p><strong>注意</strong>：</p><ul><li>-b 和–brokerAddr 是等价的，-b是缩写，其余同理；(后面的全称都是两个短横线，由于md自动转译了，就不一一改了，太多了)</li><li>本文所有配置信息，基于RocketMQ 4.7.1整理；</li><li>一般来说[]内的参数为可选参数，但是经过验证，<strong>不指定nameserver地址，是会报错的</strong>；</li></ul><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">create topic to 172.24.30.194:10911 success.</span><br><span class="line">create topic to 172.24.30.193:10911 success.</span><br><span class="line">create topic to 172.24.30.192:10911 success.</span><br><span class="line">TopicConfig [topicName=zhurunhua, readQueueNums=8, writeQueueNums=8, perm=RW-, topicFilterType=SINGLE_TAG, topicSysFlag=0, order=false]</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="deleteTopic"><a href="#deleteTopic" class="headerlink" title="deleteTopic"></a>deleteTopic</h3><p><strong>作用</strong>：从broker和nameserver删除topic</p><p><strong>命令</strong>：mqadmin deleteTopic -c [-h] [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-c,–clusterName</td><td>指定cluster名称</td><td></td></tr><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>name server地址列表</td><td>以分号分割，例如：192.168.0.1:9876;192.168.0.2:9876</td></tr><tr><td>-t,–topic</td><td>设置topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">delete topic [zhurunhua] from cluster [xdf-test1] success.</span><br><span class="line">delete topic [zhurunhua] from NameServer success.</span><br></pre></td></tr></table></figure><h3 id="topicList"><a href="#topicList" class="headerlink" title="topicList"></a>topicList</h3><p><strong>作用</strong>：从nameserver列出所有topic</p><p><strong>命令</strong>：mqadmin topicList [-c] [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-c,–clusterModel</td><td>指定cluster模式</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"><span class="meta prompt_">%</span><span class="language-bash">DLQ%xxoo</span></span><br><span class="line"><span class="meta prompt_">%</span><span class="language-bash">RETRY%dfub-order</span></span><br><span class="line">BenchmarkTest</span><br><span class="line">testschedule</span><br><span class="line">...</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h3 id="updateTopicPerm"><a href="#updateTopicPerm" class="headerlink" title="updateTopicPerm"></a>updateTopicPerm</h3><p><strong>作用</strong>：更新topic权限</p><p><strong>命令</strong>：mqadmin updateTopicPerm [-b ] [-c ] [-h] [-n ] -p -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-b,–brokerAddr</td><td>设置更新哪个broker</td><td></td></tr><tr><td>-c,–clusterName</td><td>设置更新哪个cluster</td><td></td></tr><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-p,–perm</td><td>设置topic的权限</td><td>取值：2、4、6；含义：2-W、4-R、6-RW</td></tr><tr><td>-t,–topic</td><td>设置修改的topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">update topic perm from 6 to 4 in 172.24.30.192:10911 success.</span><br><span class="line">TopicConfig [topicName=zhurunhua, readQueueNums=8, writeQueueNums=8, perm=R--, topicFilterType=SINGLE_TAG, topicSysFlag=0, order=false].</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：需要同时指定nameserver和brokerAddr</p><h3 id="topicRoute"><a href="#topicRoute" class="headerlink" title="topicRoute"></a>topicRoute</h3><p><strong>作用</strong>：检查topic路由信息</p><p><strong>命令</strong>：mqadmin topicRoute [-h] [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">&#123;</span><br><span class="line">        <span class="string">&quot;brokerDatas&quot;</span>:[</span><br><span class="line">                &#123;</span><br><span class="line">                        <span class="string">&quot;brokerAddrs&quot;</span>:&#123;0:<span class="string">&quot;172.24.30.193:10911&quot;</span>,1:<span class="string">&quot;172.24.30.192:11911&quot;</span></span><br><span class="line">                        &#125;,</span><br><span class="line">                        <span class="string">&quot;brokerName&quot;</span>:<span class="string">&quot;broker-b&quot;</span>,</span><br><span class="line">                        <span class="string">&quot;cluster&quot;</span>:<span class="string">&quot;xdf-test1&quot;</span></span><br><span class="line">                &#125;,</span><br><span class="line">                &#123;</span><br><span class="line">                        <span class="string">&quot;brokerAddrs&quot;</span>:&#123;0:<span class="string">&quot;172.24.30.194:10911&quot;</span>,1:<span class="string">&quot;172.24.30.193:11911&quot;</span></span><br><span class="line">                        &#125;,</span><br><span class="line">                        <span class="string">&quot;brokerName&quot;</span>:<span class="string">&quot;broker-c&quot;</span>,</span><br><span class="line">                        <span class="string">&quot;cluster&quot;</span>:<span class="string">&quot;xdf-test1&quot;</span></span><br><span class="line">                &#125;,</span><br><span class="line">                &#123;</span><br><span class="line">                        <span class="string">&quot;brokerAddrs&quot;</span>:&#123;0:<span class="string">&quot;172.24.30.192:10911&quot;</span>,1:<span class="string">&quot;172.24.30.194:11911&quot;</span></span><br><span class="line">                        &#125;,</span><br><span class="line">                        <span class="string">&quot;brokerName&quot;</span>:<span class="string">&quot;broker-a&quot;</span>,</span><br><span class="line">                        <span class="string">&quot;cluster&quot;</span>:<span class="string">&quot;xdf-test1&quot;</span></span><br><span class="line">                &#125;</span><br><span class="line">        ],</span><br><span class="line">        <span class="string">&quot;filterServerTable&quot;</span>:&#123;&#125;,</span><br><span class="line">        <span class="string">&quot;queueDatas&quot;</span>:[</span><br><span class="line">                &#123;</span><br><span class="line">                        <span class="string">&quot;brokerName&quot;</span>:<span class="string">&quot;broker-c&quot;</span>,</span><br><span class="line">                        <span class="string">&quot;perm&quot;</span>:6,</span><br><span class="line">                        <span class="string">&quot;readQueueNums&quot;</span>:8,</span><br><span class="line">                        <span class="string">&quot;topicSynFlag&quot;</span>:0,</span><br><span class="line">                        <span class="string">&quot;writeQueueNums&quot;</span>:8</span><br><span class="line">                &#125;,</span><br><span class="line">                &#123;</span><br><span class="line">                        <span class="string">&quot;brokerName&quot;</span>:<span class="string">&quot;broker-b&quot;</span>,</span><br><span class="line">                        <span class="string">&quot;perm&quot;</span>:6,</span><br><span class="line">                        <span class="string">&quot;readQueueNums&quot;</span>:8,</span><br><span class="line">                        <span class="string">&quot;topicSynFlag&quot;</span>:0,</span><br><span class="line">                        <span class="string">&quot;writeQueueNums&quot;</span>:8</span><br><span class="line">                &#125;,</span><br><span class="line">                &#123;</span><br><span class="line">                        <span class="string">&quot;brokerName&quot;</span>:<span class="string">&quot;broker-a&quot;</span>,</span><br><span class="line">                        <span class="string">&quot;perm&quot;</span>:4,</span><br><span class="line">                        <span class="string">&quot;readQueueNums&quot;</span>:8,</span><br><span class="line">                        <span class="string">&quot;topicSynFlag&quot;</span>:0,</span><br><span class="line">                        <span class="string">&quot;writeQueueNums&quot;</span>:8</span><br><span class="line">                &#125;</span><br><span class="line">        ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="topicStatus"><a href="#topicStatus" class="headerlink" title="topicStatus"></a>topicStatus</h3><p><strong>作用</strong>：检查topic的状态信息</p><p><strong>命令</strong>：mqadmin topicStatus [-h] [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">broker-a                          0     0                     0                       </span><br><span class="line">broker-a                          1     0                     0                       </span><br><span class="line">broker-a                          2     0                     0                       </span><br><span class="line">broker-a                          3     0                     0                       </span><br><span class="line">broker-a                          4     0                     0                       </span><br><span class="line">broker-a                          5     0                     0                       </span><br><span class="line">broker-a                          6     0                     0                       </span><br><span class="line">broker-a                          7     0                     0                       </span><br><span class="line">broker-b                          0     0                     0                       </span><br><span class="line">broker-b                          1     0                     0                       </span><br><span class="line">broker-b                          2     0                     0                       </span><br><span class="line">broker-b                          3     0                     0                       </span><br><span class="line">broker-b                          4     0                     0                       </span><br><span class="line">broker-b                          5     0                     0                       </span><br><span class="line">broker-b                          6     0                     0                       </span><br><span class="line">broker-b                          7     0                     0                       </span><br><span class="line">broker-c                          0     0                     0                       </span><br><span class="line">broker-c                          1     0                     0                       </span><br><span class="line">broker-c                          2     0                     0                       </span><br><span class="line">broker-c                          3     0                     0                       </span><br><span class="line">broker-c                          4     0                     0                       </span><br><span class="line">broker-c                          5     0                     0                       </span><br><span class="line">broker-c                          6     0                     0                       </span><br><span class="line">broker-c                          7     0                     0                       </span><br></pre></td></tr></table></figure><h3 id="topicClusterList"><a href="#topicClusterList" class="headerlink" title="topicClusterList"></a>topicClusterList</h3><p><strong>作用</strong>：获取topic的集群信息</p><p><strong>命令</strong>：mqadmin topicClusterList [-h] [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">xdf-test1</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="cleanUnusedTopic"><a href="#cleanUnusedTopic" class="headerlink" title="cleanUnusedTopic"></a>cleanUnusedTopic</h3><p><strong>作用</strong>：清理未使用的topic</p><p><strong>命令</strong>：mqadmin cleanUnusedTopic [-b ] [-c ] [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>broker地址</td><td></td></tr><tr><td>-c,–cluster</td><td>集群名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">success</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：需同时指定nameserver和broker地址，若只指定了nameserver，会报错：wait response on the channel &lt;172.24.30.192:9876&gt; timeout, 4904(ms)</p><h2 id="Message相关"><a href="#Message相关" class="headerlink" title="Message相关"></a>Message相关</h2><h3 id="sendMessage"><a href="#sendMessage" class="headerlink" title="sendMessage"></a>sendMessage</h3><p><strong>作用</strong>：发送消息</p><p><strong>命令</strong>：mqadmin sendMessage [-b ] [-c ] [-h] [-i ] [-k ] [-n ] -p -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–broker</td><td>设置发送消息的目标broker</td><td></td></tr><tr><td>-c,–tags</td><td>Message tags</td><td></td></tr><tr><td>-i,–qid</td><td>设置目标queue</td><td></td></tr><tr><td>-k,–key</td><td>消息key</td><td></td></tr><tr><td>-p,–body</td><td>消息体</td><td>UTF-8编码，字符串</td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">broker-b                          6     SEND_OK                 AC110001DD437EA987AC6F4D48590000</span><br><span class="line"></span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：</p><ul><li>这里 返回的MsgId，实际上是UniqueKey，通过queryById是查不出来的，但是通过queryMsgByUniqueKey能查到；</li><li>Tag的使用：一个应用尽可能用一个Topic，而消息子类型则可以用tags来标识。tags可以由应用自由设置，只有生产者在发送消息设置了tags，消费方在订阅消息时才可以利用tags通过broker做消息过滤：message.setTags(“TagA”)。</li></ul><h3 id="sendMsgStatus"><a href="#sendMsgStatus" class="headerlink" title="sendMsgStatus"></a>sendMsgStatus</h3><p><strong>作用</strong>：发送消息到broker</p><p><strong>命令</strong>：mqadmin sendMsgStatus -b [-c ] [-h] [-n ] [-s ]</p><p><strong>注意</strong>：并不是真正发送消息，只是检测消息的发送状态（sendStatus、rt）</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerName</td><td>broker名称</td><td></td></tr><tr><td>-c,–count</td><td>发送消息数量</td><td>默认：50</td></tr><tr><td>-s,–messageSize</td><td>消息大小</td><td>默认：128</td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">rt:1ms, SendResult=SendResult [sendStatus=SEND_OK, msgId=AC110001F3237EA987AC6F72C5140001, offsetMsgId=AC181EC000002A9F000000014136B4B6, messageQueue=MessageQueue [topic=broker-a, brokerName=broker-a, queueId=0], queueOffset=58]rt:1ms, SendResult=SendResult [sendStatus=SEND_OK, msgId=AC110001F3237EA987AC6F72C5160002, offsetMsgId=AC181EC000002A9F000000014136B597, messageQueue=MessageQueue [topic=broker-a, brokerName=broker-a, queueId=0], queueOffset=59]rt:5ms, SendResult=SendResult [sendStatus=SEND_OK, msgId=AC110001F3237EA987AC6F72C5170003, offsetMsgId=AC181EC000002A9F000000014136B678, messageQueue=MessageQueue [topic=broker-a, brokerName=broker-a, queueId=0], queueOffset=60]</span><br><span class="line">[root@localhost-001 bin]</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="queryMsgByKey"><a href="#queryMsgByKey" class="headerlink" title="queryMsgByKey"></a>queryMsgByKey</h3><p><strong>作用</strong>：根据key查询消息</p><p><strong>命令</strong>：mqadmin queryMsgByKey [-h] -k [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr><tr><td>-k,–msgKey</td><td>消息key</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">AC110001E0BD7EA987AC6F5319D10000                      5                                        0</span><br><span class="line">AC110001E1347EA987AC6F5353DD0000                      7                                        0</span><br><span class="line">AC110001E1727EA987AC6F537C7E0000                      7                                        1</span><br><span class="line">AC110001E2697EA987AC6F55DD160000                      2                                        0</span><br><span class="line">AC110001E5CC7EA987AC6F5AD1B30000                      1                                        0</span><br><span class="line">AC110001DE177EA987AC6F4F1BE30000                      0                                        0</span><br><span class="line">AC110001DE4D7EA987AC6F4F5A730000                      0                                        1</span><br><span class="line">AC110001DE817EA987AC6F4FA88E0000                      3                                        0</span><br><span class="line">AC110001DF467EA987AC6F509C6C0000                      3                                        1</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="queryMsgById"><a href="#queryMsgById" class="headerlink" title="queryMsgById"></a>queryMsgById</h3><p><strong>作用</strong>：根据消息id查询消息</p><p><strong>命令</strong>： [-d ] [-g ] [-h] -i [-n ] [-s ] [-u ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-d,–clientId</td><td>消费者客户端id</td><td></td></tr><tr><td>-g,–consumerGroup</td><td>订阅组名称</td><td></td></tr><tr><td>-i,–msgId</td><td>消息id</td><td></td></tr><tr><td>-s,–sendMessage</td><td>resend message</td><td></td></tr><tr><td>-u,–unitName</td><td>unit name</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">OffsetID:            AC181EC100002A9F000000018A727660</span><br><span class="line">Topic:               zhurunhua</span><br><span class="line">Tags:                [测试message]</span><br><span class="line">Keys:                [test-key]</span><br><span class="line">Queue ID:            2</span><br><span class="line">Queue Offset:        0</span><br><span class="line">CommitLog Offset:    6617724512</span><br><span class="line">Reconsume Times:     0</span><br><span class="line">Born Timestamp:      2023-03-01 15:08:31,339</span><br><span class="line">Store Timestamp:     2023-03-01 15:08:31,345</span><br><span class="line">Born Host:           172.24.30.192:25687</span><br><span class="line">Store Host:          172.24.30.193:10911</span><br><span class="line">System Flag:         0</span><br><span class="line">Properties:          &#123;KEYS=test-key, UNIQ_KEY=AC110001EBBC7EA987AC6F6552EB0000, CLUSTER=xdf-test1, WAIT=<span class="literal">true</span>, TAGS=测试message&#125;</span><br><span class="line">Message Body Path:   /tmp/rocketmq/msgbodys/AC110001EBBC7EA987AC6F6552EB0000` </span><br></pre></td></tr></table></figure><h3 id="queryMsgByUniqueKey"><a href="#queryMsgByUniqueKey" class="headerlink" title="queryMsgByUniqueKey"></a>queryMsgByUniqueKey</h3><p><strong>作用</strong>：根据唯一key查询消息</p><p><strong>命令</strong>：mqadmin queryMsgByUniqueKey [-d ] [-g ] [-h] -i [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-d,–clientId</td><td>消费者客户端id</td><td></td></tr><tr><td>-g,–consumerGroup</td><td>订阅组名称</td><td></td></tr><tr><td>-i,–msgId</td><td>消息id</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">Topic:               zhurunhua</span><br><span class="line">Tags:                [测试message]</span><br><span class="line">Keys:                [test-key1]</span><br><span class="line">Queue ID:            1</span><br><span class="line">Queue Offset:        0</span><br><span class="line">CommitLog Offset:    5865661490</span><br><span class="line">Reconsume Times:     0</span><br><span class="line">Born Timestamp:      2023-03-01 14:57:02,899</span><br><span class="line">Store Timestamp:     2023-03-01 14:57:02,904</span><br><span class="line">Born Host:           172.24.30.192:56596</span><br><span class="line">Store Host:          172.24.30.194:10911</span><br><span class="line">System Flag:         0</span><br><span class="line">Properties:          &#123;KEYS=test-key1, UNIQ_KEY=AC110001E5CC7EA987AC6F5AD1B30000, CLUSTER=xdf-test1, WAIT=<span class="literal">true</span>, TAGS=测试message&#125;</span><br><span class="line">Message Body Path:   /tmp/rocketmq/msgbodys/AC110001E5CC7EA987AC6F5AD1B30000</span><br><span class="line">[root@localhost-001 bin]` </span><br></pre></td></tr></table></figure><h3 id="queryMsgByOffset"><a href="#queryMsgByOffset" class="headerlink" title="queryMsgByOffset"></a>queryMsgByOffset</h3><p><strong>作用</strong>：根据offset查询消息</p><p><strong>命令</strong>：mqadmin queryMsgByOffset -b [-h] -i [-n ] -o -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr><tr><td>-b,–brokerName</td><td>broker名称</td><td>这里需要注意填写的是broker 的名称，不是broker 的地址，broker名称可以在clusterList 查到</td></tr><tr><td>-i,–queueId</td><td>队列id</td><td>默认是8个，queue id从0到7</td></tr><tr><td>-o,–offset</td><td>offset 值</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">OffsetID:            AC181EC100002A9F000000018A6399BE</span><br><span class="line">Topic:               zhurunhua</span><br><span class="line">Tags:                [null]</span><br><span class="line">Keys:                [test-key]</span><br><span class="line">Queue ID:            6</span><br><span class="line">Queue Offset:        0</span><br><span class="line">CommitLog Offset:    6616750526</span><br><span class="line">Reconsume Times:     0</span><br><span class="line">Born Timestamp:      2023-03-01 14:42:15,770</span><br><span class="line">Store Timestamp:     2023-03-01 14:42:15,775</span><br><span class="line">Born Host:           172.24.30.192:26838</span><br><span class="line">Store Host:          172.24.30.193:10911</span><br><span class="line">System Flag:         0</span><br><span class="line">Properties:          &#123;MIN_OFFSET=0, MAX_OFFSET=1, KEYS=test-key, UNIQ_KEY=AC110001DD437EA987AC6F4D48590000, CLUSTER=xdf-test1, WAIT=<span class="literal">true</span>&#125;</span><br><span class="line">Message Body Path:   /tmp/rocketmq/msgbodys/AC110001DD437EA987AC6F4D48590000` </span><br></pre></td></tr></table></figure><h3 id="printMsg"><a href="#printMsg" class="headerlink" title="printMsg"></a>printMsg</h3><p><strong>作用</strong>：打印消息详情</p><p><strong>命令</strong>：mqadmin printMsg [-b ] [-c ] [-d ] [-e ] [-h] [-n ] [-s ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr><tr><td>-b,–beginTimestamp</td><td>开始时间戳</td><td>时间戳 或 yyyy-MM-dd#HH:mm:ss:SSS格式的时间</td></tr><tr><td>-c,–charsetName</td><td>字符编码名称</td><td>例如：UTF-8,GBK</td></tr><tr><td>-d,–printBody</td><td>是否打印消息体</td><td>true 、false</td></tr><tr><td>-e,–endTimestamp</td><td>结束时间戳</td><td></td></tr><tr><td>-s,–subExpression</td><td>Subscribe Expression</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-c, queueId=7]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-b, queueId=6]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-a, queueId=5]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-b, queueId=7]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-a, queueId=6]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-a, queueId=7]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-c, queueId=0]minOffset=0, maxOffset=0, MessageQueue [topic=zhurunhua, brokerName=broker-c, queueId=1]minOffset=0, maxOffset=1, MessageQueue [topic=zhurunhua, brokerName=broker-b, queueId=0]MSGID: AC110001DE177EA987AC6F4F1BE30000 MessageExt [brokerName=broker-b, queueId=0, storeSize=195, queueOffset=0, sysFlag=0, bornTimestamp=1600757055459, bornHost=/172.24.30.192:34188, storeTimestamp=1600757055464, storeHost=/172.24.30.193:10911, msgId=AC181EC100002A9F000000018A64C05D, commitLogOffset=6616825949, bodyCRC=1801232349, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message&#123;topic=&#x27;zhurunhua&#x27;, flag=0, properties=&#123;MIN_OFFSET=0, MAX_OFFSET=2, KEYS=test-key1, UNIQ_KEY=AC110001DE177EA987AC6F4F1BE30000, CLUSTER=xdf-test1, WAIT=true&#125;, body=[116, 101, 115, 116, 45, 98, 111, 100, 121, 49], transactionId=&#x27;null&#x27;&#125;] BODY: test-body1</span><br><span class="line">MSGID: AC110001DE4D7EA987AC6F4F5A730000 MessageExt [brokerName=broker-b, queueId=0, storeSize=195, queueOffset=1, sysFlag=0, bornTimestamp=1600757071475, bornHost=/172.24.30.192:39631, storeTimestamp=1600757071480, storeHost=/172.24.30.193:10911, msgId=AC181EC100002A9F000000018A6543C4, commitLogOffset=6616859588, bodyCRC=1801232349, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message&#123;topic=&#x27;zhurunhua&#x27;, flag=0, properties=&#123;MIN_OFFSET=0, MAX_OFFSET=2, KEYS=test-key1, UNIQ_KEY=AC110001DE4D7EA987AC6F4F5A730000, CLUSTER=xdf-test1, WAIT=true&#125;, body=[116, 101, 115, 116, 45, 98, 111, 100, 121, 49], transactionId=&#x27;null&#x27;&#125;] </span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="printMsgByQueue"><a href="#printMsgByQueue" class="headerlink" title="printMsgByQueue"></a>printMsgByQueue</h3><p><strong>作用</strong>：通过queue id查询消息详情</p><p><strong>命令</strong>： -a [-b ] [-c ] [-d ] [-e ] [-f ] [-h] -i [-n ] [-p ] [-s ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-a,–brokerName</td><td>broker名称</td><td></td></tr><tr><td>-b,–beginTimestamp</td><td>开始时间戳</td><td>时间戳 或 yyyy-MM-dd#HH:mm:ss:SSS</td></tr><tr><td>-e,–endTimestamp</td><td>结束时间戳</td><td></td></tr><tr><td>-c,–charsetName</td><td>字符编码名称</td><td>例如：UTF-8,GBK</td></tr><tr><td>-d,–printBody</td><td>print body</td><td></td></tr><tr><td>-f,–calculate</td><td>calculate by tag</td><td>true｜false(default)</td></tr><tr><td>-i,–queueId</td><td>队列id</td><td></td></tr><tr><td>-p,–print msg</td><td>是否打印消息</td><td>true｜false(default)</td></tr><tr><td>-s,–subExpression</td><td>Subscribe Expression</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin printMsgByQueue -n 172.24.30.192:9876 -a broker-b -t zhurunhua -i 0 -c UTF-8</span><br></pre></td></tr></table></figure><h3 id="consumeMessage"><a href="#consumeMessage" class="headerlink" title="consumeMessage"></a>consumeMessage</h3><p><strong>作用</strong>：消费消息</p><p><strong>命令</strong>：mqadmin consumeMessage [-b ] [-c ] [-e ] [-g ] [-h] [-i ] [-n ] [-o ] [-s ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerName</td><td>broker名称</td><td></td></tr><tr><td>-c,–MessageNumber</td><td>消费消息数量</td><td></td></tr><tr><td>-s,–beginTimestamp</td><td>开始时间</td><td>currentTimeMillis或yyyy-MM-dd#HH:mm:ss:SSS格式表示的时间</td></tr><tr><td>-e,–endTimestamp</td><td>结束时间</td><td></td></tr><tr><td>-g,–consumerGroup</td><td>消费者组名称</td><td></td></tr><tr><td>-i,–queueId</td><td>queue id</td><td></td></tr><tr><td>-o,–offset</td><td>queue offset</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin consumeMessage -n 172.24.30.192:9876 -t zhurunhua -b broker-a -c 3 -g zhurunhua</span><br></pre></td></tr></table></figure><h2 id="Group相关"><a href="#Group相关" class="headerlink" title="Group相关"></a>Group相关</h2><h3 id="updateSubGroup"><a href="#updateSubGroup" class="headerlink" title="updateSubGroup"></a>updateSubGroup</h3><p><strong>作用</strong>：修改或创建订阅组</p><p><strong>命令</strong>：mqadmin updateSubGroup [-a ] [-b ] [-c ] [-d ] -g [-h] [-i ] [-m ] [-n ] [-q ] [-r ] [-s ] [-w ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-a,–notifyConsumerIdsChanged</td><td>notify consumerId changed</td><td>true(默认)｜false</td></tr><tr><td>-b,–brokerAddr</td><td>broker 地址，表示订阅组建在该broker</td><td></td></tr><tr><td>-c,–clusterName</td><td>cluster名称，表示订阅组建在该集群</td><td></td></tr><tr><td>-d,–consumeBroadcastEnable</td><td>是否允许广播方式消费</td><td>true｜false(默认)</td></tr><tr><td>-g,–groupName</td><td>设置订阅组名称</td><td></td></tr><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-i,–brokerId</td><td>设置从哪个broker开始消费</td><td>默认0</td></tr><tr><td>-m,–consumeFromMinEnable</td><td>是否容许从队列的最小位置开始消费</td><td>true｜false(默认)</td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-q,–retryQueueNums</td><td>消费失败的消息放到一个重试队列，每个订阅组配置几个重试队列</td><td>默认1</td></tr><tr><td>-r,–retryMaxTimes</td><td>重试消费最大次数</td><td>超过则投递到死信队列，不再投递，并报警；默认16</td></tr><tr><td>-s,–consumeEnable</td><td>消费功能是否开启</td><td>true(默认)｜false</td></tr><tr><td>-w,–whichBrokerWhenConsumeSlowly</td><td>发现消息堆积后，将Consumer的消费请求重定向到另外一台Slave机器</td><td>配置broker id，默认1</td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">create subscription group to 172.24.30.194:10911 success.</span><br><span class="line">create subscription group to 172.24.30.193:10911 success.</span><br><span class="line">create subscription group to 172.24.30.192:10911 success.</span><br><span class="line">SubscriptionGroupConfig [groupName=zhurunhua-consume-group, consumeEnable=true, consumeFromMinEnable=true, consumeBroadcastEnable=true, retryQueueNums=8, retryMaxTimes=3, brokerId=0, whichBrokerWhenConsumeSlowly=1, notifyConsumerIdsChangedEnable=true][root@localhost-001 bin]</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：必须指定clusterName</p><h3 id="deleteSubGroup"><a href="#deleteSubGroup" class="headerlink" title="deleteSubGroup"></a>deleteSubGroup</h3><p><strong>作用</strong>：删除订阅组</p><p><strong>命令</strong>：mqadmin deleteSubGroup [-b ] [-c ] -g [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-b,–brokerAddr</td><td>broker地址，表示在该broker删除订阅组</td><td></td></tr><tr><td>-c,–clusterName</td><td>cluster 名称，表示在该集群删除订阅组</td><td></td></tr><tr><td>-g,–groupName</td><td>指定删除的订阅组名称</td><td></td></tr><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver 服务地址列表</td><td></td></tr></tbody></table><p><strong>示例</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@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">delete subscription group [zhurunhua-consume-group] from broker [172.24.30.194:10911] in cluster [xdf-test1] success.</span><br><span class="line">delete subscription group [zhurunhua-consume-group] from broker [172.24.30.193:10911] in cluster [xdf-test1] success.</span><br><span class="line">delete subscription group [zhurunhua-consume-group] from broker [172.24.30.192:10911] in cluster [xdf-test1] success.</span><br><span class="line">delete topic [%RETRY%zhurunhua-consume-group] from cluster [xdf-test1] success.</span><br><span class="line">delete topic [%RETRY%zhurunhua-consume-group] from NameServer success.</span><br><span class="line">delete topic [%DLQ%zhurunhua-consume-group] from cluster [xdf-test1] success.</span><br><span class="line">delete topic [%DLQ%zhurunhua-consume-group] from NameServer success.</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：必须指定clusterName</p><h3 id="cloneGroupOffset"><a href="#cloneGroupOffset" class="headerlink" title="cloneGroupOffset"></a>cloneGroupOffset</h3><p><strong>作用</strong>：从其他组克隆offset</p><p><strong>命令</strong>： mqadmin cloneGroupOffset -d [-h] [-n ] [-o ] -s -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-s,–srcGroup</td><td>源消费者组名称</td><td></td></tr><tr><td>-d,–destGroup</td><td>目标消费者组名称</td><td></td></tr><tr><td>-o,–offline</td><td><em>the group or the topic is offline</em></td><td>true</td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin cloneGroupOffset -n 172.24.30.192:9876 -s zhurunhua-1 -d zhurunhua-2 -t zhurunhua </span><br></pre></td></tr></table></figure><h2 id="统计分析"><a href="#统计分析" class="headerlink" title="统计分析"></a>统计分析</h2><h3 id="brokerStatus"><a href="#brokerStatus" class="headerlink" title="brokerStatus"></a>brokerStatus</h3><p><strong>作用</strong>：获取broker运行时的状态数据</p><p><strong>命令</strong>： mqadmin brokerStatus [-b ] [-c ] [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>broker地址</td><td></td></tr><tr><td>-c,–clusterName</td><td>集群名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">EndTransactionQueueSize         : 0</span><br><span class="line">EndTransactionThreadPoolQueueCapacity: 100000</span><br><span class="line">bootTimestamp                   : 1600660736545</span><br><span class="line">brokerVersion                   : 355</span><br><span class="line">brokerVersionDesc               : V4_7_1</span><br><span class="line">commitLogDirCapacity            : Total : 40.0 GiB, Free : 23.9 GiB.</span><br><span class="line">commitLogDiskRatio              : 0.40273704594017096</span><br><span class="line">commitLogMaxOffset              : 5389336601</span><br><span class="line">commitLogMinOffset              : 5368709120</span><br><span class="line">consumeQueueDiskRatio           : 0.40273704594017096</span><br><span class="line">dispatchBehindBytes             : 0</span><br><span class="line">dispatchMaxBuffer               : 0</span><br><span class="line">earliestMessageTimeStamp        : 1600310170573</span><br><span class="line">getFoundTps                     : 0.0 0.033330000333300004 0.046661689419795226</span><br><span class="line">getMessageEntireTimeMax         : 8</span><br><span class="line">getMissTps                      : 17.998200179982 27.1639502716395 26.75381292662116</span><br><span class="line">getTotalTps                     : 17.998200179982 27.1972802719728 26.800474616040955</span><br><span class="line">getTransferedTps                : 0.0 0.033330000333300004 0.046661689419795226</span><br><span class="line">msgGetTotalTodayMorning         : 2185</span><br><span class="line">msgGetTotalTodayNow             : 4046</span><br><span class="line">msgGetTotalYesterdayMorning     : 0</span><br><span class="line">msgPutTotalTodayMorning         : 2918</span><br><span class="line">msgPutTotalTodayNow             : 5357</span><br><span class="line">msgPutTotalYesterdayMorning     : 0</span><br><span class="line">pageCacheLockTimeMills          : 0</span><br><span class="line">pullThreadPoolQueueCapacity     : 100000</span><br><span class="line">pullThreadPoolQueueHeadWaitTimeMills: 0</span><br><span class="line">pullThreadPoolQueueSize         : 0</span><br><span class="line">putMessageAverageSize           : 428.9402650737353</span><br><span class="line">putMessageDistributeTime        : [&lt;=0ms]:3 [0~10ms]:1 [10~50ms]:0 [50~100ms]:0 [100~200ms]:0 [200~500ms]:0 [500ms~1s]:0 [1~2s]:0 [2~3s]:0 [3~4s]:0 [4~5s]:0 [5~10s]:0 [10s~]:0 </span><br><span class="line">putMessageEntireTimeMax         : 10</span><br><span class="line">putMessageSizeTotal             : 2297833</span><br><span class="line">putMessageTimesTotal            : 5357</span><br><span class="line">putTps                          : 0.0 0.06666000066660001 0.09498986774744028</span><br><span class="line">queryThreadPoolQueueCapacity    : 20000</span><br><span class="line">queryThreadPoolQueueHeadWaitTimeMills: 0</span><br><span class="line">queryThreadPoolQueueSize        : 0</span><br><span class="line">remainHowManyDataToFlush        : 0 B</span><br><span class="line">remainTransientStoreBufferNumbs : 2147483647</span><br><span class="line">runtime                         : [ 1 days, 5 hours, 32 minutes, 46 seconds ]</span><br><span class="line">...</span><br><span class="line">...</span><br><span class="line">[root@localhost-001 bin]` </span><br></pre></td></tr></table></figure><p><strong>注意</strong>：使用-c会查处所有broker状态信息，包含所有主、从，使用-b只能指定一个broker查询</p><h3 id="brokerConsumeStats"><a href="#brokerConsumeStats" class="headerlink" title="brokerConsumeStats"></a>brokerConsumeStats</h3><p><strong>作用</strong>：获取消耗统计数据</p><p><strong>命令</strong>：mqadmin brokerConsumeStats -b [-h] [-l ] [-n ] [-o ] [-t ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>broker地址</td><td></td></tr><tr><td>-l,–level</td><td><em>threshold of print diff</em></td><td></td></tr><tr><td>-o,–order</td><td><em>order topic</em></td><td></td></tr><tr><td>-t,–timeoutMillis</td><td>请求超时时间</td><td>单位：毫秒</td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">%</span><span class="language-bash">RETRY%dfub-roster-data           dfub-roster-data                  broker-a                          0     13612                 13612                 0                     2023-03-01 17:37:20</span></span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          0     197                   197                   0                     2023-03-01 15:44:00</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          1     203                   203                   0                     2023-03-01 16:21:09</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          2     202                   202                   0                     2023-03-01 11:52:00</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          3     195                   195                   0                     2023-03-01 15:16:21</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          4     196                   196                   0                     2023-03-01 16:07:32</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          5     201                   201                   0                     2023-03-01 17:25:41</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          6     203                   203                   0                     2023-03-01 16:24:30</span><br><span class="line">dfub-jiaowu-roster-push-data-t    dfub-roster-data                  broker-a                          7     207                   207                   0                     2023-03-01 17:33:16</span><br><span class="line">......</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="producerConnection"><a href="#producerConnection" class="headerlink" title="producerConnection"></a>producerConnection</h3><p><strong>作用</strong>：查询Producer 的网络连接，该命令只打印当前与cluster 连接的producer 网络连接信息</p><p><strong>命令</strong>：mqadmin producerConnection -g [-h] [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-g,–producerGroup</td><td>生产者所属组名</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="consumerConnection"><a href="#consumerConnection" class="headerlink" title="consumerConnection"></a>consumerConnection</h3><p><strong>作用</strong>：查询Consumer的网络连接，该命令只打印当前与cluster连接的consumer网络连接信息</p><p><strong>命令</strong>：mqadmin consumerConnection -g [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-g,–consumerGroup</td><td>消费者所属组名</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">001  172.24.202.77@org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer_1 172.24.202.77:29200    JAVA     V4_5_1</span><br><span class="line">002  10.155.86.170@org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer_1 10.155.86.170:60246    JAVA     V4_5_1</span><br><span class="line">003  172.24.202.79@org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer_1 172.24.202.79:28141    JAVA     V4_5_1</span><br><span class="line">004  10.155.87.190@org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer_1 10.155.87.190:62559    JAVA     V4_5_1</span><br><span class="line"></span><br><span class="line">Below is subscription:001  Topic: $&#123;rocketmq.producer.customized-lesson-delay-message-topic&#125; SubExpression: *</span><br><span class="line">002  Topic: %RETRY%dfub-lesson                       SubExpression: *</span><br><span class="line">ConsumeType: CONSUME_PASSIVELY</span><br><span class="line">MessageModel: CLUSTERING</span><br><span class="line">ConsumeFromWhere: CONSUME_FROM_LAST_OFFSET</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="consumerProgress"><a href="#consumerProgress" class="headerlink" title="consumerProgress"></a>consumerProgress</h3><p><strong>作用</strong>：查看订阅组消费状态</p><p><strong>命令</strong>：mqadmin consumerProgress [-g ] [-h] [-n ] [-s ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-g,–groupName</td><td>消费者所属组名</td><td></td></tr><tr><td>-s,–showClientIP</td><td>显示每个queue的客户端IP</td><td>true</td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">%</span><span class="language-bash">RETRY%dfub-lvb-student-transfer  broker-a                          0     16                    16                    172.24.202.77        0                     N/A</span></span><br><span class="line"><span class="meta prompt_">%</span><span class="language-bash">RETRY%dfub-lvb-student-transfer  broker-b                          0     0                     0                     172.24.202.77        0                     N/A</span></span><br><span class="line"><span class="meta prompt_">%</span><span class="language-bash">RETRY%dfub-lvb-student-transfer  broker-c                          0     96                    96                    172.24.202.77        0                     N/A</span></span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          0     1                     1                     172.24.202.77        0                     2023-03-01 15:55:15</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          1     2                     2                     172.24.202.77        0                     N/A</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          2     0                     0                     172.24.202.77        0                     N/A</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          3     1                     1                     172.24.202.77        0                     N/A</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          4     3                     3                     172.24.202.77        0                     N/A</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          5     3                     3                     172.24.202.77        0                     2020-09-18 16:02:10</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          6     7                     7                     172.24.202.77        0                     2020-09-21 10:38:30</span><br><span class="line">dfub-banke-transfer-lesson-data-  broker-a                          7     1                     1                     172.24.202.77        0                     2020-09-17 21:27:31</span><br></pre></td></tr></table></figure><h3 id="consumerStatus"><a href="#consumerStatus" class="headerlink" title="consumerStatus"></a>consumerStatus</h3><p><strong>作用</strong>：查看消费者的内部数据结构</p><p><strong>命令</strong>：mqadmin consumerStatus -g [-h] [-i ] [-n ] [-s]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-i,–clientId</td><td>消费者客户端id</td><td></td></tr><tr><td>-g,–consumerGroup</td><td>消费者所属组名</td><td></td></tr><tr><td>-s,–jstack</td><td>在消费者进程中运行jstack命令</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">001  172.24.202.77@org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer_10 V4_5_1               1600767940334/172.24.202.77@org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer_10</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Same subscription in the same group of consumer</span><br><span class="line"></span><br><span class="line">Rebalance OK</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="clusterList"><a href="#clusterList" class="headerlink" title="clusterList"></a>clusterList</h3><p><strong>作用</strong>：查看集群信息</p><p><strong>命令</strong>：mqadmin clusterList [-h] [-i ] [-m] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-i,–interval</td><td>指定间隔数</td><td>单位：秒</td></tr><tr><td>-m,–moreStats</td><td>打印更多信息</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">xdf-test1         broker-a                                   2918           2185           2519           1909</span><br><span class="line">xdf-test1         broker-a                                   3786              0           2519              0</span><br><span class="line">xdf-test1         broker-b                                 155267         180068         116494          34032</span><br><span class="line">xdf-test1         broker-b                                 180526              0         116494              0</span><br><span class="line">xdf-test1         broker-c                                   7443          14816          92479         102952</span><br><span class="line">xdf-test1         broker-c                                   7463           6598          92479              0</span><br><span class="line"></span><br><span class="line">xdf-test1         broker-a                                   2918           2185           2520           1910</span><br><span class="line">xdf-test1         broker-a                                   3786              0           2520              0</span><br><span class="line">xdf-test1         broker-b                                 155267         180068         116602          34040</span><br><span class="line">xdf-test1         broker-b                                 180526              0         116602              0</span><br><span class="line">xdf-test1         broker-c                                   7443          14816          92587         103070</span><br><span class="line">xdf-test1         broker-c                                   7463           6598          92587              0` </span><br></pre></td></tr></table></figure><p><strong>注意</strong>：若指定了-i，则会每经过指定秒数刷新一次，不指定则只打印一次</p><h3 id="statsAll"><a href="#statsAll" class="headerlink" title="statsAll"></a>statsAll</h3><p><strong>作用</strong>：查看topic和consumer的tps信息</p><p><strong>命令</strong>：mqadmin statsAll [-a] [-h] [-n ] [-t ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-a,–activeTopic</td><td>只打印活跃的topic信息</td><td></td></tr><tr><td>-t,–topic</td><td>只打印指定的topic</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">zhurunhua                                                                     0        0.00                         13    NO_CONSUMER</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="checkMsgSendRT"><a href="#checkMsgSendRT" class="headerlink" title="checkMsgSendRT"></a>checkMsgSendRT</h3><p><strong>作用</strong>：检查消息发送响应时间</p><p><strong>命令</strong>：mqadmin checkMsgSendRT [-a ] [-h] [-n ] -s -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-a,–amount</td><td>消息数量</td><td>默认：100</td></tr><tr><td>-s,–size</td><td>消息大小</td><td>默认：128 Byte</td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">broker-b                          0     <span class="literal">true</span>                    211</span><br><span class="line">broker-b                          1     <span class="literal">true</span>                    2</span><br><span class="line">broker-b                          2     <span class="literal">true</span>                    7</span><br><span class="line">broker-b                          3     <span class="literal">true</span>                    2</span><br><span class="line">broker-b                          4     <span class="literal">true</span>                    3</span><br><span class="line">broker-b                          5     <span class="literal">true</span>                    3</span><br><span class="line">broker-b                          6     <span class="literal">true</span>                    3</span><br><span class="line">broker-b                          7     <span class="literal">true</span>                    3</span><br><span class="line">broker-c                          0     <span class="literal">true</span>                    6</span><br><span class="line">broker-c                          1     <span class="literal">true</span>                    3</span><br><span class="line">Avg RT: 3.56</span><br><span class="line">[root@localhost-001 bin]` </span><br><span class="line"></span><br><span class="line">![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)</span><br></pre></td></tr></table></figure><h3 id="clusterRT"><a href="#clusterRT" class="headerlink" title="clusterRT"></a>clusterRT</h3><p><strong>作用</strong>：列出所有cluster消息发送响应时间</p><p><strong>命令</strong>：mqadmin clusterRT [-a ] [-c ] [-h] [-i ] [-m ] [-n ] [-p ] -s</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-a,–amount</td><td>消息数量</td><td>默认：100</td></tr><tr><td>-c,–cluster</td><td>指定cluster名称</td><td>不指定则打印所有</td></tr><tr><td>-i,–interval</td><td>打印间隔</td><td>默认：10秒</td></tr><tr><td>-m,–machine room</td><td>机器room name</td><td>默认：noname</td></tr><tr><td>-p,–print log</td><td>以日志形式打印</td><td>true</td></tr><tr><td>-s,–size</td><td>消息大小</td><td>默认：128 Byte</td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line"></span><br><span class="line">xdf-test1                 broker-b                  1.82      50                0               </span><br><span class="line">xdf-test1                 broker-c                  1.53      50                0               </span><br><span class="line">xdf-test1                 broker-a                  1.27      50                0               </span><br><span class="line">xdf-test1                 broker-b                  1.78      50                0               </span><br><span class="line">xdf-test1                 broker-c                  1.49      50                0               </span><br><span class="line">xdf-test1                 broker-a                  0.88      50                0               </span><br><span class="line">xdf-test1                 broker-b                  0.90      50                0               </span><br><span class="line">xdf-test1                 broker-c                  1.08      50                0               </span><br><span class="line">xdf-test1                 broker-a                  0.94      50                0               </span><br><span class="line">xdf-test1                 broker-b                  0.86      50                0               </span><br><span class="line">xdf-test1                 broker-c                  0.92      50                0               </span><br><span class="line">xdf-test1                 broker-a                  0.49      50                0   </span><br><span class="line"></span><br><span class="line">[root@localhost-001 <span class="built_in">log</span>]</span><br><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">2023-03-01 17:56:26|noname|xdf-test1|broker-b|2</span><br><span class="line">2023-03-01 17:56:26|noname|xdf-test1|broker-c|2</span><br><span class="line">2023-03-01 17:56:27|noname|xdf-test1|broker-a|1</span><br><span class="line">2023-03-01 17:56:30|noname|xdf-test1|broker-b|1</span><br><span class="line">2023-03-01 17:56:30|noname|xdf-test1|broker-c|2</span><br><span class="line">2023-03-01 17:56:30|noname|xdf-test1|broker-a|1</span><br><span class="line">2023-03-01 17:56:33|noname|xdf-test1|broker-b|1</span><br><span class="line">2023-03-01 17:56:33|noname|xdf-test1|broker-c|1</span><br><span class="line">2023-03-01 17:56:33|noname|xdf-test1|broker-a|1` </span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="queryCq"><a href="#queryCq" class="headerlink" title="queryCq"></a>queryCq</h3><p><strong>作用</strong>：查询cq命令</p><p><strong>命令</strong>： mqadmin queryCq [-b ] [-c ] [-g ] [-h] -i [-n ] -q -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–broker</td><td>broker地址</td><td></td></tr><tr><td>-c,–count</td><td>设置数量</td><td></td></tr><tr><td>-g,–consumer</td><td>设置消费者组名称</td><td></td></tr><tr><td>-i,–index</td><td>设置queue开始索引</td><td></td></tr><tr><td>-q,–queue</td><td>设置queue数量</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">Queue data: </span><br><span class="line">max: 1, min: 0</span><br><span class="line">======================================</span><br><span class="line">idx: 0</span><br><span class="line">ConsumeQueueData&#123;physicOffset=6609928052, physicSize=395, tagsCode=0, extendDataJson=&#x27;null&#x27;, bitMap=&#x27;null&#x27;, eval=false, msg=&#x27;null&#x27;&#125;</span><br><span class="line">======================================</span><br><span class="line">[root@localhost-001 bin]</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h2 id="运维管理"><a href="#运维管理" class="headerlink" title="运维管理"></a>运维管理</h2><h3 id="wipeWritePerm"><a href="#wipeWritePerm" class="headerlink" title="wipeWritePerm"></a>wipeWritePerm</h3><p><strong>作用</strong>：清除特定Brokerd的写权限</p><p><strong>命令</strong>：mqadmin wipeWritePerm -b [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerName</td><td>broker name</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">wipe write perm of broker[broker-a] in name server[172.24.30.192:9876] OK, 187</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="resetOffsetByTime"><a href="#resetOffsetByTime" class="headerlink" title="resetOffsetByTime"></a>resetOffsetByTime</h3><p><strong>作用</strong>：通过时间戳重置消费者offset（不用重启客户端）</p><p><strong>命令</strong>：mqadmin resetOffsetByTime [-c] [-f ] -g [-h] [-n ] -s -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-c,–cplus</td><td>重置客户端offset</td><td></td></tr><tr><td>-f,–force</td><td>通过时间戳强制回滚</td><td>true、false，默认为true</td></tr><tr><td>-g,–group</td><td>消费者所属组名</td><td></td></tr><tr><td>-s,–timestamp</td><td>设置时间戳</td><td>选项：now、currentTimeMillis、yyyy-MM-dd#HH:mm:ss:SSS</td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin resetOffsetByTime -n 172.24.30.192:9876 -g zhurunhua-1 -s now -t zhurunhua </span><br></pre></td></tr></table></figure><h3 id="cleanExpiredCQ"><a href="#cleanExpiredCQ" class="headerlink" title="cleanExpiredCQ"></a>cleanExpiredCQ</h3><p><strong>作用</strong>：清理过期的消费者队列</p><p><strong>命令</strong>：mqadmin cleanExpiredCQ [-b ] [-c ] [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>broker地址</td><td></td></tr><tr><td>-c,–cluster</td><td>集群名称</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">success</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><h3 id="startMonitoring"><a href="#startMonitoring" class="headerlink" title="startMonitoring"></a>startMonitoring</h3><p><strong>作用</strong>：开启监控</p><p><strong>命令</strong>：mqadmin startMonitoring [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin startMonitoring  -n 172.24.30.192:9876</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="allocateMQ"><a href="#allocateMQ" class="headerlink" title="allocateMQ"></a>allocateMQ</h3><p><strong>作用</strong>：分配MQ</p><p><strong>命令</strong>：mqadmin allocateMQ [-h] -i [-n ] -t</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-i,–ipList</td><td>ip列表</td><td></td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="配置相关"><a href="#配置相关" class="headerlink" title="配置相关"></a>配置相关</h2><h3 id="getNamesrvConfig"><a href="#getNamesrvConfig" class="headerlink" title="getNamesrvConfig"></a>getNamesrvConfig</h3><p><strong>作用</strong>：获取name server 配置</p><p><strong>命令</strong>：mqadmin getNamesrvConfig [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found <span class="keyword">for</span> logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">============172.24.30.192:9876============</span><br><span class="line">serverChannelMaxIdleTimeSeconds                   =  120</span><br><span class="line">listenPort                                        =  9876</span><br><span class="line">serverCallbackExecutorThreads                     =  0</span><br><span class="line">serverAsyncSemaphoreValue                         =  64</span><br><span class="line">serverSocketSndBufSize                            =  65535</span><br><span class="line">rocketmqHome                                      =  /neworiental/rocketmq-nameserver/rocketmq-all-4.7.1-bin-release</span><br><span class="line">clusterTest                                       =  <span class="literal">false</span></span><br><span class="line">serverSelectorThreads                             =  3</span><br><span class="line">useEpollNativeSelector                            =  <span class="literal">false</span></span><br><span class="line">orderMessageEnable                                =  <span class="literal">false</span></span><br><span class="line">serverPooledByteBufAllocatorEnable                =  <span class="literal">true</span></span><br><span class="line">kvConfigPath                                      =  /neworiental/rocketmq-nameserver/namesrv/kvConfig.json</span><br><span class="line">serverWorkerThreads                               =  8</span><br><span class="line">serverSocketRcvBufSize                            =  65535</span><br><span class="line">productEnvName                                    =  center</span><br><span class="line">serverOnewaySemaphoreValue                        =  256</span><br><span class="line">configStorePath                                   =  /neworiental/rocketmq-nameserver/rocketmq-all-4.7.1-bin-release/conf/nameserver.conf</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：经测试，-n每次只能指定一个nameserver地址</p><p><img data-src="https://img-blog.csdnimg.cn/img_convert/c39448e21ad34c5cfdc3394d123aa66f.png"></p><h3 id="updateNamesrvConfig"><a href="#updateNamesrvConfig" class="headerlink" title="updateNamesrvConfig"></a>updateNamesrvConfig</h3><p><strong>作用</strong>：修改name server 配置</p><p><strong>命令</strong>：mqadmin updateNamesrvConfig [-h] -k [-n ] -v</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-k,–key</td><td>config key值</td><td></td></tr><tr><td>-v,–value</td><td>config value值</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">update name server config success![172.24.30.192:9876]</span><br><span class="line">serverSelectorThreads : 5</span><br><span class="line">[root@localhost-001 bin]</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：每次只能修改一个nameserver</p><h3 id="updateKvConfig"><a href="#updateKvConfig" class="headerlink" title="updateKvConfig"></a>updateKvConfig</h3><p><strong>作用</strong>：创建或修改KV配置信息</p><p><strong>命令</strong>：mqadmin updateKvConfig [-h] -k [-n ] -s -v</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-s,–namespace</td><td>namespace值</td><td></td></tr><tr><td>-k,–key</td><td>key值</td><td></td></tr><tr><td>-v,–value</td><td>value值</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="deleteKvConfig"><a href="#deleteKvConfig" class="headerlink" title="deleteKvConfig"></a>deleteKvConfig</h3><p><strong>作用</strong>：删除KV配置信息</p><p><strong>命令</strong>： mqadmin deleteKvConfig [-h] -k [-n ] -s</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-k,–key</td><td>key值</td><td></td></tr><tr><td>-s,–namespace</td><td>namespace值</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="updateBrokerConfig"><a href="#updateBrokerConfig" class="headerlink" title="updateBrokerConfig"></a>updateBrokerConfig</h3><p><strong>作用</strong>：更新broker配置文件</p><p><strong>命令</strong>：mqadmin updateBrokerConfig [-b ] [-c ] [-h] -k [-n ] -v</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-b,–brokerAddr</td><td>broker地址，如果未指定-c，则必填</td><td></td></tr><tr><td>-c,–clusterName</td><td>cluster名称，如果未指定-b，则必填</td><td></td></tr><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-k,–key</td><td>配置的key值</td><td></td></tr><tr><td>-v,–value</td><td>配置的value值</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">[root@localhost-001 bin]</span><br><span class="line">RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).</span><br><span class="line">RocketMQLog:WARN Please initialize the logger system properly.</span><br><span class="line">update broker config success, 172.24.30.194:10911</span><br><span class="line">update broker config success, 172.24.30.193:10911</span><br><span class="line">update broker config success, 172.24.30.192:10911</span><br><span class="line">[root@localhost-001 bin]</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="getBrokerConfig"><a href="#getBrokerConfig" class="headerlink" title="getBrokerConfig"></a>getBrokerConfig</h3><p><strong>作用</strong>：获取broker配置</p><p><strong>命令</strong>：mqadmin getBrokerConfig [-b ] [-c ] [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>broker地址，如果未指定-c，则必填</td><td></td></tr><tr><td>-c,–clusterName</td><td>cluster名称，如果未指定-b，则必填</td><td></td></tr></tbody></table><p><strong>示例</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></pre></td><td class="code"><pre><span class="line">./mqadmin getBrokerConfig -n 172.24.30.192:9876 -c xdf-test1</span><br><span class="line"></span><br><span class="line">./mqadmin getBrokerConfig -n 172.24.30.192:9876 -b localhost:10911</span><br><span class="line"></span><br><span class="line">由于配置项过多，此处省略</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>注意</strong>：-c会打印出集群内的所有broker配置信息，-b可以打印指定的broker(只能指定一个)</p><h3 id="updateAclConfig"><a href="#updateAclConfig" class="headerlink" title="updateAclConfig"></a>updateAclConfig</h3><p><strong>作用</strong>：修改ACL配置yaml文件</p><p><strong>命令</strong>：mqadmin updateAclConfig -a -b | -c [-g ] [-h] [-i ] [-m ] [-n ] [-s ] [-t ] [-u ] [-w ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-a,–accessKey</td><td>在acl配置文件中配置accessKey</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>指定修改acl配置文件的broker地址</td><td></td></tr><tr><td>-c,–clusterName</td><td>指定修改acl配置文件的cluster名称</td><td></td></tr><tr><td>-g,–groupPerms</td><td>配置组的权限列表</td><td>例如: groupD&#x3D;DENY,groupD&#x3D;SUB</td></tr><tr><td>-i,–defaultTopicPerm</td><td>设置默认的topic权限</td><td></td></tr><tr><td>-m,–admin</td><td>设置admin标识</td><td></td></tr><tr><td>-s,–secretKey</td><td>设置secretKey</td><td></td></tr><tr><td>-t,–topicPerms</td><td>设置topic权限列表</td><td>例如: topicA&#x3D;DENY,topicD&#x3D;SUB</td></tr><tr><td>-u,–defaultGroupPerm</td><td>设置默认的组权限</td><td></td></tr><tr><td>-w,–whiteRemoteAddress</td><td>设置ip白名单</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="deleteAccessConfig"><a href="#deleteAccessConfig" class="headerlink" title="deleteAccessConfig"></a>deleteAccessConfig</h3><p><strong>作用</strong>：删除ACL配置</p><p><strong>命令</strong>：mqadmin deleteAccessConfig -a -b | -c [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-a,–accessKey</td><td>设置accessKey</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>指定broker地址</td><td></td></tr><tr><td>-c,–clusterName</td><td>指定cluster名称</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="clusterAclConfigVersion"><a href="#clusterAclConfigVersion" class="headerlink" title="clusterAclConfigVersion"></a>clusterAclConfigVersion</h3><p><strong>作用</strong>：列出所有ACL配置版本信息</p><p><strong>命令</strong>：mqadmin clusterAclConfigVersion -b | -c [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>指定broker地址</td><td></td></tr><tr><td>-c,–clusterName</td><td>指定cluster名称</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin clusterAclConfigVersion -n 172.24.30.192:9876 -b 172.24.30.192:10911</span><br></pre></td></tr></table></figure><h3 id="updateGlobalWhiteAddr"><a href="#updateGlobalWhiteAddr" class="headerlink" title="updateGlobalWhiteAddr"></a>updateGlobalWhiteAddr</h3><p><strong>作用</strong>：修改acl配置的全局白名单</p><p><strong>命令</strong>：mqadmin updateGlobalWhiteAddr -b | -c -g [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>指定broker地址</td><td></td></tr><tr><td>-c,–clusterName</td><td>指定cluster名称</td><td></td></tr><tr><td>-g,–globalWhiteRemoteAddresses</td><td>设置全局白名单列表</td><td>例如: 10.10.103.<em>,192.168.0.</em></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="getAccessConfigSubCommand"><a href="#getAccessConfigSubCommand" class="headerlink" title="getAccessConfigSubCommand"></a>getAccessConfigSubCommand</h3><p><strong>作用</strong>：列出所有acl配置信息</p><p><strong>命令</strong>：mqadmin getAccessConfigSubCommand -b | -c [-h] [-n ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-b,–brokerAddr</td><td>指定broker地址</td><td></td></tr><tr><td>-c,–clusterName</td><td>指定cluster名称</td><td></td></tr></tbody></table><p><strong>示例</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">./mqadmin getAccessConfigSubCommand -n 172.24.30.192:9876 -b 172.24.30.192:10911</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="updateOrderConf"><a href="#updateOrderConf" class="headerlink" title="updateOrderConf"></a>updateOrderConf</h3><p><strong>作用</strong>：创建、修改或删除order conf</p><p><strong>命令</strong>：mqadmin updateOrderConf [-h] -m [-n ] -t [-v ]</p><table><thead><tr><th>参数</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>-h,–help</td><td>打印help信息</td><td></td></tr><tr><td>-n,–namesrvAddr</td><td>nameserver服务地址列表</td><td></td></tr><tr><td>-m,–method</td><td>操作类型</td><td>例如：put、get、delete</td></tr><tr><td>-t,–topic</td><td>topic名称</td><td></td></tr><tr><td>-v,–orderConf</td><td>设置order conf</td><td></td></tr></tbody></table><p><strong>示例</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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="官方误笔"><a href="#官方误笔" class="headerlink" title="官方误笔"></a>官方误笔</h2><blockquote><p>已提交PR，并被官方合并至master分支</p></blockquote><ul><li><strong>这儿acl少了个a，to应该是from</strong></li></ul><p><img data-src="https://img-blog.csdnimg.cn/img_convert/3a727149f1f526ea33739429cec80f53.png"></p><ul><li><strong>这儿做的是查询操作，但是写的是update</strong></li></ul><p><img data-src="https://img-blog.csdnimg.cn/img_convert/b18a1eb2be5166701915cd9fcf34b883.png"></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://blog.csdn.net/sinat_14840559/article/details/111934325">https://blog.csdn.net/sinat_14840559/article/details/111934325</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个地方是写描述的地方&lt;/p&gt;</summary>
    
    
    
    <category term="RocketMQ" scheme="http://next.skyheng.com/categories/RocketMQ/"/>
    
    
    <category term="RocketMQ" scheme="http://next.skyheng.com/tags/RocketMQ/"/>
    
  </entry>
  
  <entry>
    <title>使用Coding持续集成结合腾讯云Serverless部署应用</title>
    <link href="http://next.skyheng.com/post/64489.html"/>
    <id>http://next.skyheng.com/post/64489.html</id>
    <published>2023-02-26T13:52:41.000Z</published>
    <updated>2025-11-30T14:41:25.911Z</updated>
    
    <content type="html"><![CDATA[<p>说到搭建网站，相信大家第一反应都是会去购买一台云服务器，然后根据网上的教程，自己在云服务器上一顿操作，最终搭建出自己的网站。</p><p>这种在云服务上搭建网站的方式，确实相比以前自己买物理服务器来搭建网站的方式节省了很多开销，自己买物理服务器的话，起步价都是好几万的，而且这种大玩意放在家里也占地方。</p><p>但是购买云服务器的时候，我们其实是要掏钱向云服务厂商租用云服务器，一般都是以年为单位租用，不管你的网站是几千人访问，还是几个人访问，都是统一的价钱，即使云服务器后面闲置不用了，也已经产生了一年的租用费用。</p><p><strong>我就在想，如果有这样”无服务器”搭建网站的方式，让我们可以不租用云服务器搭建网站，而是直接在云服务厂商里创建一个应用的方式搭建网站，再根据实际的流量来计费的话，那么我们就能节省这一笔租用云服务器的费用，而且也能降低搭建网站的门槛。</strong></p><span id="more"></span><h2 id="Serverless-是什么？"><a href="#Serverless-是什么？" class="headerlink" title="Serverless 是什么？"></a><strong>Serverless 是什么？</strong></h2><p>Serverless 是指 “无服务器架构”，这里的 <strong>“无服务器” 并不是指程序不需要服务器运行</strong>，而是<strong>指我们的开发工作不需要关注服务器底层的资源</strong>，就仿佛服务器不存在一样。</p><p>我们在通过租用云服务器搭建网站的时候，需要考虑要用怎样配置的云服务器，比如多大的内存、多大的带宽、多少核心的 CPU 等等。</p><p>而出现 Serverless 技术之后，这些东西都不需要我们考虑了，Serverless 会帮我们根据网站流量的大小分配相应的资源，也就是有自动伸缩的能力，同时也无需再对服务器进行运维了，无需不断的打系统补丁、应用补丁、无需进行数据备份、软件配置等工作了。</p><p>这么一看，是不是觉得 Serverless 很像一个「保姆」，帮我们打理一切繁琐的事情，让我们只需要关注应用本身。</p><p>但是没有服务器，如何来将程序、应用运行起来呢？这里要介绍的是 Serverless 下包含的两个概念：<strong>函数即服务（FaaS）， 后端即服务（BaaS）</strong>。</p><p><strong>什么是「函数即服务」？</strong></p><p>每一个函数就是一个服务，函数之间相互独立。函数（也可说方法）颗粒度更小，可以帮助应用获得极致弹性。让用户抛弃了对服务器的配置和管理，仅需编写和上传核心业务代码，交由平台完成部署、调度、流量分发、弹性伸缩等能力。</p><p>我们来看一张基于 FaaS 的架构图：</p><p><img data-src="https://pic4.zhimg.com/80/v2-ade9443b9f935c119b6b1a127f964f6b_1440w.webp" alt="img"></p><p>基于 FaaS 的服务器底层的关系从下到上依次是这样的：物理服务器（IaaS） &gt; 虚拟机（PaaS） &gt; 容器（PaaS） &gt; 函数（FaaS）</p><p><strong>什么是「后端即服务」？</strong></p><p>其实大家已经使用很久了，这里的后端，指的就是各种云产品和云服务，例如对象存储，云数据库、云缓存等。这些产品或服务，用户直接开通即可使用，无需考虑部署、扩容、备份、优化、安全等各种运维工作，做到了开箱即用，无需自己去进行服务器或应用的维护和管理，因此同样也是 Serverless 的一部分。</p><h2 id="“无服务器”搭建网站"><a href="#“无服务器”搭建网站" class="headerlink" title="“无服务器”搭建网站"></a><strong>“无服务器”搭建网站</strong></h2><p>腾讯云 Serverless 提供了很多基于无服务器应用框架 Serverless 架构的应用部署，开发者无需关心底层资源，即可快速部署完整可用的 Serverless 应用架构，具有资源编排、自动伸缩、事件驱动等能力，帮助开发者通过联动云资源，迅速构建 Serverless 应用。</p><h2 id="基于serverless-yml文件"><a href="#基于serverless-yml文件" class="headerlink" title="基于serverless.yml文件"></a>基于serverless.yml文件</h2><p>创建serverless.yml文件</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">component:</span> <span class="string">website</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">navigation</span></span><br><span class="line"><span class="attr">app:</span> <span class="string">navigation</span></span><br><span class="line"></span><br><span class="line"><span class="attr">inputs:</span></span><br><span class="line">  <span class="attr">src:</span></span><br><span class="line">    <span class="attr">src:</span> <span class="string">./src</span></span><br><span class="line">    <span class="attr">index:</span> <span class="string">index.html</span></span><br><span class="line">    <span class="attr">error:</span> <span class="string">index.html</span></span><br><span class="line">  <span class="attr">region:</span> <span class="string">ap-guangzhou</span></span><br><span class="line">  <span class="attr">bucketName:</span> <span class="string">navigation</span></span><br><span class="line">  <span class="attr">protocol:</span> <span class="string">https</span></span><br></pre></td></tr></table></figure><p>创建.env文件、填写值可从环境变量中获取</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">TENCENT_APP_ID</span>=<span class="string"></span></span><br><span class="line"><span class="attr">TENCENT_SECRET_ID</span>=<span class="string"></span></span><br><span class="line"><span class="attr">TENCENT_SECRET_KEY</span>=<span class="string"></span></span><br><span class="line"><span class="attr">TENCENT_TOKEN</span>=<span class="string"></span></span><br></pre></td></tr></table></figure><p>静态配置的 Jenkinsfile</p><blockquote><p>静态配置的 Jenkinsfile 将不会保存在代码仓库中。<br>所有的构建任务将统一使用该静态配置，不再使用代码仓库中的 Jenkinsfile</p></blockquote><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></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages &#123;</span><br><span class="line">    stage(<span class="string">&#x27;检出&#x27;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        checkout([<span class="variable">$class</span>: <span class="string">&#x27;GitSCM&#x27;</span>,</span><br><span class="line">        branches: [[name: GIT_BUILD_REF]],</span><br><span class="line">        userRemoteConfigs: [[</span><br><span class="line">          url: GIT_REPO_URL,</span><br><span class="line">          credentialsId: CREDENTIALS_ID</span><br><span class="line">        ]]])</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    stage(<span class="string">&#x27;初始化 Node.js&#x27;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;date&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_SECRET_ID=$TENCENT_TEMP_SECRET_ID &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_SECRET_KEY=$TENCENT_TEMP_SECRET_KEY &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_TOKEN=$TENCENT_TEMP_TOKEN &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_APP_ID=$TENCENT_APP_ID &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo SERVERLESS_PLATFORM_VENDOR=tencent &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo SERVERLESS_PLATFORM_STAGE=$SERVERLESS_PLATFORM_STAGE &gt;&gt; .env&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    stage(<span class="string">&#x27;安装 Severless 环境&#x27;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;pnpm install -g serverless-tencent&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;slt -v&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    stage(<span class="string">&#x27;部署应用&#x27;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;slt deploy --debug&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="基于Jenkinsfile文件"><a href="#基于Jenkinsfile文件" class="headerlink" title="基于Jenkinsfile文件"></a>基于Jenkinsfile文件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages  &#123;</span><br><span class="line">    stage(<span class="string">&quot;检出&quot;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        checkout(</span><br><span class="line">          [<span class="variable">$class</span>: <span class="string">&#x27;GitSCM&#x27;</span>,</span><br><span class="line">          branches: [[name: GIT_BUILD_REF]],</span><br><span class="line">          userRemoteConfigs: [[</span><br><span class="line">            url: GIT_REPO_URL,</span><br><span class="line">              credentialsId: CREDENTIALS_ID</span><br><span class="line">            ]]]</span><br><span class="line">        )</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">        </span><br><span class="line">    stage(<span class="string">&quot;初始化 Node.js&quot;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;date&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_SECRET_ID=$TENCENT_TEMP_SECRET_ID &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_SECRET_KEY=$TENCENT_TEMP_SECRET_KEY &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_TOKEN=$TENCENT_TEMP_TOKEN &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo TENCENT_APP_ID=$TENCENT_APP_ID &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo SERVERLESS_PLATFORM_VENDOR=tencent &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;echo SERVERLESS_PLATFORM_STAGE=$SERVERLESS_PLATFORM_STAGE &gt;&gt; .env&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;&#x27;</span><span class="string">&#x27;cat &gt; npm.sh &lt;&lt; EOF</span></span><br><span class="line"><span class="string">#! /bin/bash</span></span><br><span class="line"><span class="string">rootPath=\\`pwd\\`</span></span><br><span class="line"><span class="string">function read_dir()&#123;</span></span><br><span class="line"><span class="string">  for file in \\`ls \\$1\\`</span></span><br><span class="line"><span class="string">  do</span></span><br><span class="line"><span class="string">    if [ -d \\$1&#x27;</span>/<span class="string">&#x27;\\$file ]; then</span></span><br><span class="line"><span class="string">      if [ \\$file != &#x27;</span>node_modules<span class="string">&#x27; ]; then</span></span><br><span class="line"><span class="string">        read_dir \\$1&#x27;</span>/<span class="string">&#x27;\\$file</span></span><br><span class="line"><span class="string">      fi</span></span><br><span class="line"><span class="string">    else</span></span><br><span class="line"><span class="string">      if [ \\$file = &#x27;</span>package.json<span class="string">&#x27; ]; then</span></span><br><span class="line"><span class="string">        cd \\$1</span></span><br><span class="line"><span class="string">        npm install</span></span><br><span class="line"><span class="string">        cd \\$rootPath</span></span><br><span class="line"><span class="string">      fi</span></span><br><span class="line"><span class="string">    fi</span></span><br><span class="line"><span class="string">  done</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">read_dir \\$1</span></span><br><span class="line"><span class="string">EOF&#x27;</span><span class="string">&#x27;&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;cat npm.sh &amp;&amp; ls -la&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    stage(<span class="string">&quot;安装 Severless 环境&quot;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;pnpm install -g serverless-tencent&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;slt -v&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    stage(<span class="string">&quot;安装依赖&quot;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;rm -rf ./node_modules&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;chmod +x ./npm.sh &amp;&amp; ./npm.sh `pwd` &amp;&amp; rm npm.sh&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    stage(<span class="string">&quot;生成配置文件&quot;</span>) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh <span class="string">&#x27;npm install -g @slsplus/cli&#x27;</span></span><br><span class="line">        sh <span class="string">&#x27;slsplus parse --output --auto-create --sls-options=\&#x27;</span>&#123;<span class="string">&quot;component&quot;</span>:<span class="string">&quot;scf&quot;</span>,<span class="string">&quot;name&quot;</span>:<span class="string">&quot;<span class="variable">$&#123;env:INSTANCE_NAME&#125;</span>&quot;</span>,<span class="string">&quot;org&quot;</span>:<span class="string">&quot;<span class="variable">$&#123;env:TENCENT_APP_ID&#125;</span>&quot;</span>,<span class="string">&quot;app&quot;</span>:<span class="string">&quot;<span class="variable">$&#123;env:APP_NAME&#125;</span>&quot;</span>,<span class="string">&quot;stage&quot;</span>:<span class="string">&quot;<span class="variable">$&#123;env:STAGE&#125;</span>&quot;</span>,<span class="string">&quot;inputs&quot;</span>:&#123;<span class="string">&quot;region&quot;</span>:<span class="string">&quot;<span class="variable">$&#123;env:REGION&#125;</span>&quot;</span>,<span class="string">&quot;runtime&quot;</span>:<span class="string">&quot;<span class="variable">$&#123;env:RUNTIME&#125;</span>&quot;</span>,<span class="string">&quot;src&quot;</span>:<span class="string">&quot;./src&quot;</span>,<span class="string">&quot;handler&quot;</span>: <span class="string">&quot;index.main_handler&quot;</span>,<span class="string">&quot;events&quot;</span>:[&#123;<span class="string">&quot;apigw&quot;</span>: &#123;<span class="string">&quot;parameters&quot;</span>: &#123;<span class="string">&quot;endpoints&quot;</span>: [&#123;<span class="string">&quot;function&quot;</span>: &#123;<span class="string">&quot;isIntegratedResponse&quot;</span>: <span class="literal">true</span>&#125;,<span class="string">&quot;method&quot;</span>: <span class="string">&quot;ANY&quot;</span>,<span class="string">&quot;path&quot;</span>: <span class="string">&quot;/static&quot;</span>&#125;],<span class="string">&quot;environment&quot;</span>: <span class="string">&quot;release&quot;</span>,<span class="string">&quot;protocols&quot;</span>: [<span class="string">&quot;http&quot;</span>,<span class="string">&quot;https&quot;</span>]&#125;&#125;&#125;]&#125;&#125;\&#x27; &amp;&amp; <span class="built_in">cat</span> serverless.yml<span class="string">&#x27;</span></span><br><span class="line"><span class="string">      &#125;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    stage(&#x27;</span>部署应用<span class="string">&#x27;) &#123;</span></span><br><span class="line"><span class="string">        steps &#123;</span></span><br><span class="line"><span class="string">            sh &quot;slt deploy --debug&quot;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">  &#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="旧版本的Jenkinsfile文件"><a href="#旧版本的Jenkinsfile文件" class="headerlink" title="旧版本的Jenkinsfile文件"></a>旧版本的Jenkinsfile文件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">    agent any</span><br><span class="line">  </span><br><span class="line">    stages &#123;</span><br><span class="line">      stage(<span class="string">&quot;Downloading code&quot;</span>) &#123;</span><br><span class="line">        steps &#123;</span><br><span class="line">            checkout(</span><br><span class="line">                [<span class="variable">$class</span>: <span class="string">&#x27;GitSCM&#x27;</span>, branches: [[name: env.GIT_BUILD_REF]],</span><br><span class="line">                userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]]</span><br><span class="line">            )      </span><br><span class="line">          &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">      stage(<span class="string">&quot;Installing plugins&quot;</span>) &#123;</span><br><span class="line">       steps &#123;  </span><br><span class="line">          sh <span class="string">&#x27;pnpm install -g serverless-tencent&#x27;</span></span><br><span class="line">          sh <span class="string">&#x27;slt -v&#x27;</span> </span><br><span class="line">         &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      stage(<span class="string">&quot;Build environment&quot;</span>) &#123;</span><br><span class="line">        steps &#123;</span><br><span class="line">            webSite()      </span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">      stage(<span class="string">&quot;Deploying serverless project&quot;</span>) &#123;</span><br><span class="line">        steps &#123;</span><br><span class="line">          sh <span class="string">&#x27;slt deploy --debug&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a><strong>总结</strong></h2><p>这次我基于腾讯云 Serverless 带大家展示了网站搭建的过程，这种方式打破了以前搭建网站需要租借云服务器的方式。</p><p>无需购买云服务器，只需要在腾讯云 Serverless 里直接创建网站的应用就完成了网站的搭建，再也不用花费精力配置环境和维护云服务器的精力，动动鼠标点击就可以轻松地完成网站的搭建了，更重要的是，它是按量付费的，能确保所有的费用，都是用在了实际的程序运行、数据存储、用户访问中，不必为未使用的计算资源而支付。</p><h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><p><a href="https://cloud.tencent.com/document/product/1154/39276">部署静态网站</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;说到搭建网站，相信大家第一反应都是会去购买一台云服务器，然后根据网上的教程，自己在云服务器上一顿操作，最终搭建出自己的网站。&lt;/p&gt;
&lt;p&gt;这种在云服务上搭建网站的方式，确实相比以前自己买物理服务器来搭建网站的方式节省了很多开销，自己买物理服务器的话，起步价都是好几万的，而且这种大玩意放在家里也占地方。&lt;/p&gt;
&lt;p&gt;但是购买云服务器的时候，我们其实是要掏钱向云服务厂商租用云服务器，一般都是以年为单位租用，不管你的网站是几千人访问，还是几个人访问，都是统一的价钱，即使云服务器后面闲置不用了，也已经产生了一年的租用费用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我就在想，如果有这样”无服务器”搭建网站的方式，让我们可以不租用云服务器搭建网站，而是直接在云服务厂商里创建一个应用的方式搭建网站，再根据实际的流量来计费的话，那么我们就能节省这一笔租用云服务器的费用，而且也能降低搭建网站的门槛。&lt;/strong&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="hexo" scheme="http://next.skyheng.com/categories/hexo/"/>
    
    <category term="coding" scheme="http://next.skyheng.com/categories/hexo/coding/"/>
    
    
    <category term="hexo" scheme="http://next.skyheng.com/tags/hexo/"/>
    
    <category term="coding" scheme="http://next.skyheng.com/tags/coding/"/>
    
  </entry>
  
  <entry>
    <title>使用Coding持续集成构建流水线自动部署自建静态网站</title>
    <link href="http://next.skyheng.com/post/61793.html"/>
    <id>http://next.skyheng.com/post/61793.html</id>
    <published>2023-02-25T12:46:37.000Z</published>
    <updated>2025-11-30T14:41:25.910Z</updated>
    
    <content type="html"><![CDATA[<p>CODING 持续集成便是专门为此工作流而设计的得力功能。通过对每次提交的代码进行自动化的代码检查、单元测试、编译构建、甚至自动部署与发布，能够大大降低开发人员的工作负担，减少许多不必要的重复劳动，持续提升代码质量与开发效率。毫无疑问，持续集成是开发者与研发团队的福音。</p><span id="more"></span><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>静态网站无需购买昂贵的服务器，建议使用先进架构：云存储 + CDN，优点：</p><ul><li>成本低：云存储&#x2F;CDN 比服务器便宜很多（比如「<a href="https://cloud.tencent.com/product/cos">腾讯云 对象存储 COS</a>」约 0.15 元&#x2F;GB&#x2F;月、<a href="https://buy.cloud.tencent.com/price/cdn">腾讯云 CDN 每月赠送 10GB</a>）；</li><li>访问快：CDN 能在全国甚至全球快速访问，比服务器更快。</li></ul><p><strong>提醒</strong>：</p><ul><li>如果网站面向中国境内用户，需要进行域名备案，然后才能绑定到境内的云存储&#x2F;CDN。本文以腾讯云为例，其他云计算厂商的流程也类似。</li><li>如果网站面向中国境外用户，可直接使用境外云存储&#x2F;CDN 搭建静态网站。</li></ul><p>静态网站有 2 种：</p><ul><li>无内容的单页应用：VUE&#x2F;React SPA；</li><li>有内容的页面：HTML 或「程序生成 HTML」；</li></ul><p><strong>警告</strong>：VUE&#x2F;React SPA 不带内容，难以被搜索引擎收录，不适合作为公司官网、个人博客。如果有 SEO 需求，推荐使用 <a href="https://www.mkdocs.org/">MkDocs</a>、<a href="https://hexo.io/zh-cn/">Hexo</a>、<a href="https://zh.nuxtjs.org/">VUE Nuxt</a>、<a href="https://nextjs.org/">React Next</a>。</p><h3 id="技术方案"><a href="#技术方案" class="headerlink" title="技术方案"></a>技术方案</h3><p>通过「持续集成」把 HTML 自动部署到「云存储」，变成静态网站。</p><ol><li>把项目代码推送到 「CODING 代码仓库」。</li><li>在「腾讯云 对象存储 COS」中创建一个「公有读私有写」的「存储桶」，并在设置中开启「静态网站」，即可获得一个<a href="https://html-cos-demo-1257110097.cos-website.ap-chengdu.myqcloud.com/">访问链接</a>，然后在「腾讯云 账号」的「访问管理」中获取「访问密钥」。</li><li>在「CODING 持续集成」中创建一个 构建任务，把下文的 <code>Jenkinsfile</code> 复制进去，设置环境变量，然后手动「立即构建」，构建成功，访问上面的链接即可看到网站。下次推送代码即可自动部署。</li><li>如果你的域名已备案，则可在「腾讯云 对象存储」的设置中绑定「自定义加速域名」，会提示开通「内容分发网络 CDN」，小型网站建议选择「按使用流量计费」（<a href="https://buy.cloud.tencent.com/price/cdn">每月赠送 10GB</a>，小型网站一般用不完），然后进入「内容分发网络 CDN」——「域名管理」——某个域名——「高级设置」——「HTTPS 配置」中，申请免费的 HTTPS 证书，并开启「HTTPS 回源」、「强制跳转 HTTPS」和「HTTP 2.0」。</li><li>在「腾讯云 对象存储 COS」中开启「自动刷新 CDN」，参考文档「<a href="https://cloud.tencent.com/document/product/436/45597">CDN 缓存刷新</a>」。</li></ol><h4 id="Jenkinsfile"><a href="#Jenkinsfile" class="headerlink" title="Jenkinsfile"></a>Jenkinsfile</h4><p>浏览<a href="https://coding-public.coding.net/p/html-cos-demo/d/html-cos-demo/git">完整代码</a>。</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></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages &#123;</span><br><span class="line">    stage(&#x27;检出&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        checkout([</span><br><span class="line">          $class: &#x27;GitSCM&#x27;,</span><br><span class="line">          branches: [[name: env.GIT_BUILD_REF]], </span><br><span class="line">          userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]</span><br><span class="line">        ])</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    stage(&#x27;部署到腾讯云存储&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh &quot;coscmd config -a $&#123;env.COS_SECRET_ID&#125; -s $&#123;env.COS_SECRET_KEY&#125; -b $&#123;env.COS_BUCKET_NAME&#125; -r $&#123;env.COS_BUCKET_REGION&#125;&quot;</span><br><span class="line">        sh &#x27;rm -rf .git&#x27;</span><br><span class="line">        sh &#x27;coscmd upload -r ./ /&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="持续集成环境变量"><a href="#持续集成环境变量" class="headerlink" title="持续集成环境变量"></a>持续集成环境变量</h4><table><thead><tr><th>变量名</th><th>含义</th><th>参考值</th></tr></thead><tbody><tr><td>COS_SECRET_ID</td><td>腾讯云访问密钥 ID</td><td>stringLength36stringLength36string36</td></tr><tr><td>COS_SECRET_KEY</td><td>腾讯云访问密钥 KEY</td><td>stringLength32stringLength323232</td></tr><tr><td>COS_BUCKET_NAME</td><td>腾讯云对象存储桶</td><td>devops-host-1257110097</td></tr><tr><td>COS_BUCKET_REGION</td><td>腾讯云对象存储区域</td><td>ap-nanjing</td></tr></tbody></table><h4 id="截图"><a href="#截图" class="headerlink" title="截图"></a>截图</h4><p><img data-src="https://help-assets.codehub.cn/enterprise/20200227174310.png" alt="腾讯云存储 COS 创建存储桶"></p><p><img data-src="https://help-assets.codehub.cn/enterprise/20200227174811.png" alt="腾讯云存储 COS 开启静态网站"></p><p><img data-src="https://help-assets.codehub.cn/enterprise/20200226224837.png" alt="腾讯云 访问密钥"></p><p><img data-src="https://help-assets.codehub.cn/enterprise/20200227180342.png" alt="腾讯云存储 COS 自定义加速域名"></p><p><img data-src="https://help-assets.codehub.cn/enterprise/20200227181247.png" alt="腾讯云 内容分发网络 开启 HTTPS"></p><p><img data-src="https://help-assets.codehub.cn/enterprise/20200723112434.png" alt="腾讯云存储 COS 自动刷新 CDN"></p><h3 id="各种语言生成-HTML"><a href="#各种语言生成-HTML" class="headerlink" title="各种语言生成 HTML"></a>各种语言生成 HTML</h3><h4 id="MKDocs"><a href="#MKDocs" class="headerlink" title="MKDocs"></a>MKDocs</h4><p>浏览<a href="https://coding-public.coding.net/p/mkdocs-cos-demo/d/mkdocs-cos-demo/git">完整代码</a>。</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></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages &#123;</span><br><span class="line">    stage(&#x27;检出&#x27;) &#123;...&#125;</span><br><span class="line">    stage(&#x27;构建&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        echo &#x27;Markdown 转成 HTML&#x27;</span><br><span class="line">        sh &#x27;pip install --upgrade mkdocs six&#x27;</span><br><span class="line">        sh &#x27;mkdocs build --clean&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    stage(&#x27;部署到云存储&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh &quot;coscmd config ...&quot;</span><br><span class="line">        sh &#x27;coscmd upload -r site/ /&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="VUE-Nuxt"><a href="#VUE-Nuxt" class="headerlink" title="VUE Nuxt"></a>VUE Nuxt</h4><p>浏览<a href="https://coding-public.coding.net/p/vue-nuxt-cos-demo/d/vue-nuxt-cos-demo/git">完整代码</a>。</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></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages &#123;</span><br><span class="line">    stage(&#x27;检出&#x27;) &#123;...&#125;</span><br><span class="line">    stage(&#x27;构建&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        echo &#x27;VUE Nuxt 生成 HTML&#x27;</span><br><span class="line">        sh &#x27;npm install&#x27;</span><br><span class="line">        sh &#x27;npm run generate&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    stage(&#x27;部署到云存储&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh &quot;coscmd config ...&quot;</span><br><span class="line">        sh &#x27;coscmd upload -r dist/ /&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="VUE"><a href="#VUE" class="headerlink" title="VUE"></a>VUE</h4><p>浏览<a href="https://coding-public.coding.net/p/vue-cos-demo/d/vue-cos-demo/git">完整代码</a>。</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></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages &#123;</span><br><span class="line">    stage(&#x27;检出&#x27;) &#123;...&#125;</span><br><span class="line">    stage(&#x27;构建&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        echo &#x27;VUE 生成 HTML&#x27;</span><br><span class="line">        sh &#x27;npm install&#x27;</span><br><span class="line">        sh &#x27;npm run build&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    stage(&#x27;部署到云存储&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh &quot;coscmd config ...&quot;</span><br><span class="line">        sh &#x27;coscmd upload -r dist/ /&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="React"><a href="#React" class="headerlink" title="React"></a>React</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><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">pipeline &#123;</span><br><span class="line">  agent any</span><br><span class="line">  stages &#123;</span><br><span class="line">    stage(&#x27;检出&#x27;) &#123;...&#125;</span><br><span class="line">    stage(&#x27;构建&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        echo &#x27;React 生成 HTML&#x27;</span><br><span class="line">        sh &#x27;npm install&#x27;</span><br><span class="line">        sh &#x27;npm run build&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    stage(&#x27;部署到云存储&#x27;) &#123;</span><br><span class="line">      steps &#123;</span><br><span class="line">        sh &quot;coscmd config ...&quot;</span><br><span class="line">        sh &#x27;coscmd upload -r build/ /&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a href="https://coding.net/help/docs/devops/ci/practice/static-website-paas.html">https://coding.net/help/docs/devops/ci/practice/static-website-paas.html</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;CODING 持续集成便是专门为此工作流而设计的得力功能。通过对每次提交的代码进行自动化的代码检查、单元测试、编译构建、甚至自动部署与发布，能够大大降低开发人员的工作负担，减少许多不必要的重复劳动，持续提升代码质量与开发效率。毫无疑问，持续集成是开发者与研发团队的福音。&lt;/p&gt;</summary>
    
    
    
    <category term="hexo" scheme="http://next.skyheng.com/categories/hexo/"/>
    
    <category term="coding" scheme="http://next.skyheng.com/categories/hexo/coding/"/>
    
    
    <category term="hexo" scheme="http://next.skyheng.com/tags/hexo/"/>
    
    <category term="coding" scheme="http://next.skyheng.com/tags/coding/"/>
    
  </entry>
  
  <entry>
    <title>Spring Cloud Alibaba 简介</title>
    <link href="http://next.skyheng.com/post/21283.html"/>
    <id>http://next.skyheng.com/post/21283.html</id>
    <published>2020-09-06T08:37:21.000Z</published>
    <updated>2025-11-30T14:41:25.915Z</updated>
    
    <content type="html"><![CDATA[<p>Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件，方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。</p><span id="more"></span><h2 id="Spring-Cloud-Alibaba"><a href="#Spring-Cloud-Alibaba" class="headerlink" title="Spring Cloud Alibaba"></a>Spring Cloud Alibaba</h2><p><a href="https://links.jianshu.com/go?to=https://github.com/alibaba/spring-cloud-alibaba">官方 github 地址</a></p><h2 id="主要功能"><a href="#主要功能" class="headerlink" title="主要功能"></a>主要功能</h2><ul><li>服务限流降级：默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入，可以在运行时通过控制台实时修改限流降级规则，还支持查看限流降级 Metrics 监控。</li><li>服务注册与发现：适配 Spring Cloud 服务注册与发现标准，默认集成了 Ribbon 的支持。</li><li>分布式配置管理：支持分布式系统中的外部化配置，配置更改时自动刷新。</li><li>消息驱动能力：基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。</li><li>分布式事务：使用 @GlobalTransactional 注解， 高效并且对业务零侵入地解决分布式事务问题。。</li><li>阿里云对象存储：阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。</li><li>分布式任务调度：提供秒级、精准、高可靠、高可用的定时（基于 Cron 表达式）任务调度服务。同时提供分布式的任务执行模型，如网格任务。网格任务支持海量子任务均匀分配到所有 Worker（schedulerx-client）上执行。</li><li>阿里云短信服务：覆盖全球的短信服务，友好、高效、智能的互联化通讯能力，帮助企业迅速搭建客户触达通道。</li></ul><h2 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h2><ul><li>Sentinel：把流量作为切入点，从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。</li><li>Nacos：一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。</li><li>RocketMQ：一款开源的分布式消息系统，基于高可用分布式集群技术，提供低延时的、高可靠的消息发布与订阅服务。</li><li>Dubbo：Apache Dubbo™ 是一款高性能 Java RPC 框架。</li><li>Seata：阿里巴巴开源产品，一个易于使用的高性能微服务分布式事务解决方案。</li><li>Alibaba Cloud ACM：一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。</li><li>Alibaba Cloud OSS: 阿里云对象存储服务（Object Storage Service，简称 OSS），是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。</li><li>Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品，提供秒级、精准、高可靠、高可用的定时（基于 Cron 表达式）任务调度服务。</li><li>Alibaba Cloud SMS: 覆盖全球的短信服务，友好、高效、智能的互联化通讯能力，帮助企业迅速搭建客户触达通道。</li></ul><h2 id="如何使用"><a href="#如何使用" class="headerlink" title="如何使用"></a>如何使用</h2><p>如何引入依赖<br>如果需要使用已发布的版本，在 dependencyManagement 中添加如下配置。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-alibaba-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.0.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure><p>然后在 dependencies 中添加自己所需使用的依赖即可使用。</p><h2 id="版本管理规范"><a href="#版本管理规范" class="headerlink" title="版本管理规范"></a>版本管理规范</h2><p>项目的版本号格式为 x.x.x 的形式，其中 x 的数值类型为数字，从 0 开始取值，且不限于 0~9 这个范围。项目处于孵化器阶段时，第一位版本号固定使用 0，即版本号为 0.x.x 的格式。<br>由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更，且 spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更，因此我们采取跟 SpringBoot 版本号一致的版本:</p><ul><li>1.5.x 版本适用于 Spring Boot 1.5.x</li><li>2.0.x 版本适用于 Spring Boot 2.0.x</li><li>2.1.x 版本适用于 Spring Boot 2.1.x<table><thead><tr><th>Spring Boot</th><th align="center">Spring Cloud</th><th align="right">Spring Cloud Alibaba</th></tr></thead><tbody><tr><td>2.1.x</td><td align="center">Greenwich</td><td align="right">0.9.x</td></tr><tr><td>2.0.x</td><td align="center">Finchley</td><td align="right">0.2.x</td></tr><tr><td>1.5.x</td><td align="center">Edgware</td><td align="right">0.1.x</td></tr><tr><td>1.5.x</td><td align="center">Dalston</td><td align="right">0.1.x</td></tr></tbody></table></li></ul><h2 id="现状"><a href="#现状" class="headerlink" title="现状"></a>现状</h2><p>之前 spring cloud alibaba 一直处于一个孵化状态。看名字就可以看出来 Spring Cloud 有着密切的关系。2019 月 7 月 24 日，Spring 官方宣布 Spring Cloud Alibaba 毕业，仓库迁移至 Alibaba Github OSS 下。这意味着 Spring Cloud Alibaba 是国内首个进入 Spring 社区的开源项目。</p><ul><li>2018 年 7 月，正式开源，进入孵化器。</li><li>2018 年 10 月，发布开源后的第一个版本 0.1.0 &amp; 0.2.0 (适配 Spring Cloud Edgware &amp; Finchley )，包含 Nacos Config, Nacos Discovery、 Sentinel 以及 OSS 4 个组件。</li><li>2018 年 12 月，发布第二个版本 0.1.1 &amp; 0.2.1，新增 Spring Cloud Stream RocketMQ Binder 和 Spring Cloud Bus RocketMQ 组件。</li><li>2019 年 4 月，发布 Preview Release 版本 0.9.0, 0.1.2 &amp; 0.2.2 (首次适配 Spring Cloud Greenwich )，新增 Dubbo Spring Cloud、Seata 组件。颠覆性地使用 Spring Cloud 客户端调用 Dubbo 服务</li><li>2019 年 7 月，Spring Cloud 官方宣布 Spring Cloud Alibaba 毕业。</li><li>2019 月 8 月，发布毕业后的第一个版本 1.5.0, 2.0.0 &amp; 2.1.0。新增 spring-cloud-alibaba-sentinel-gateway 模块以完善 Sentinel 对 Spring Cloud 体系 Gateway 的支持。</li></ul><p><a href="https://spring.io/projects/spring-cloud-alibaba">Spring 社区 spring cloud alibaba 官方地址</a></p><ul><li>我们都知道 Spring Restful Api 的规范性是我们喜欢的，规范代表着通用。而 dubbo 目前看来性能的收益也是让大家能感受到的。而 Spring Cloud Alibaba 的出现兼容这俩种微服务生态的优势。让鱼与熊掌不可兼得的情况提供了一个更好的方案。</li><li>个人觉得 Spring Cloud Alibaba 为喜欢 cloud、dubbo 俩种微服务的整合提供了一个较好的方案。但是会让感觉商业气息有点浓烈。毕竟阿里也是主要是为了推自己的产品服务</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件，方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Spring Cloud Alibaba 使用</title>
    <link href="http://next.skyheng.com/post/34255.html"/>
    <id>http://next.skyheng.com/post/34255.html</id>
    <published>2020-09-06T08:31:56.000Z</published>
    <updated>2025-11-30T14:41:25.915Z</updated>
    
    <content type="html"><![CDATA[<p>Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件，方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。<br>依托 Spring Cloud Alibaba，您只需要添加一些注解和少量配置，就可以将 Spring Cloud 应用接入阿里微服务解决方案，通过阿里中间件来迅速搭建分布式应用系统。</p><span id="more"></span><h3 id="一-为什么使用？"><a href="#一-为什么使用？" class="headerlink" title="一. 为什么使用？"></a>一. 为什么使用？</h3><p>很多人可能会问，有了 spring cloud 这个微服务的框架，为什么又要使用 spring cloud alibaba 这个框架了？最重要的原因在于 spring cloud 中的几乎所有的组件都使用 Netflix 公司的产品，然后在其基础上做了一层封装。然而 Netflix 的服务发现组件 Eureka 已经停止更新，我们公司在使用的时候就发现过其一个细小的 Bug；而其他的众多组件预计会在明年(即 2020 年)停止维护。所以急需其他的一些替代产品，也就是 spring cloud alibaba，目前正处于蓬勃发展的态式。</p><h3 id="二-注册中心-Nacos"><a href="#二-注册中心-Nacos" class="headerlink" title="二. 注册中心 Nacos"></a>二. 注册中心 Nacos</h3><p>nacos 是阿里巴巴研发的一个集注册中心与配置中心于一体的管理平台，使用其他非常的简单。下载地址为：<br><a href="https://github.com/alibaba/nacos/releases">https://github.com/alibaba/nacos/releases</a>，nacos 的主页如下图所示：</p><p>其中默认的登录名和密码是：nacos&#x2F;nacos</p><h4 id="2-1-更改用户名和密码"><a href="#2-1-更改用户名和密码" class="headerlink" title="2.1 更改用户名和密码"></a>2.1 更改用户名和密码</h4><p>A. 分别执行 conf 目录下的 nacos-mysql.sql 两个脚本文件，生成的数据表如下：</p><p>B. 重新配置密码<br>新建一个 springboot 的项目，引入如下的依赖：</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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p>生成密码的 Java 代码：<br>&#x2F;&#x2F; 密码加密处理</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">   <span class="type">BCryptPasswordEncoder</span> <span class="variable">bCryptPasswordEncoder</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BCryptPasswordEncoder</span>();</span><br><span class="line">   <span class="comment">// 生成的密码为：$2a$10$04MGTL.cJNZPpR3rFt/I2.43F.V75NH.5wdK.jngaO9Mc91mfonAO</span></span><br><span class="line">    System.out.println(bCryptPasswordEncoder.encode(<span class="string">&quot;admin&quot;</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>执行如下sql命令：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">insert into</span> users <span class="keyword">values</span>(<span class="string">&#x27;nacos&#x27;</span>,<span class="string">&#x27;$2a$10$04MGTL.cJNZPpR3rFt/I2.43F.V75NH.5wdK.jngaO9Mc91mfonAO&#x27;</span>, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">insert into</span> roles <span class="keyword">values</span>(<span class="string">&#x27;nacos&#x27;</span>, <span class="string">&#x27;ROLE_ADMIN&#x27;</span>)</span><br></pre></td></tr></table></figure><p>C. 配置数据库的连接<br>在 conf 目录下的 application.properties 目录下加入如下内容：</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.datasource.platform</span>=<span class="string">mysql</span></span><br><span class="line"><span class="attr">db.num</span>=<span class="string">1</span></span><br><span class="line"><span class="attr">db.url.0</span>=<span class="string">jdbc:mysql://mysql:3306/cloud-alibaba?useSSL=false&amp;serverTimezone=UTC&amp;serverTimezone=Asia/Shanghai</span></span><br><span class="line"><span class="attr">db.user</span>=<span class="string">root</span></span><br><span class="line"><span class="attr">db.password</span>=<span class="string"></span></span><br></pre></td></tr></table></figure><h4 id="2-2-nacos-集群配置"><a href="#2-2-nacos-集群配置" class="headerlink" title="2.2 nacos 集群配置"></a>2.2 nacos 集群配置</h4><p>A. 将 conf 目录下的 cluster.conf.example 拷贝一份重命名为 cluster.conf，在文件中加入所有集群节点的 ip 和端口号，文件内容如下：<br>127.0.0.1:8848<br>127.0.0.1:9948<br>B. 修改 windows 启动文件 <code>startup.cmd</code> 的配置，修改内容如下：<br>set MODE&#x3D;”standalone”  #默认的配置<br>set MODE&#x3D;”cluster”     #修改后的内容<br><strong>注：如果是 Linux 环境不用作任何的修改。</strong><br>C.启动两个 nacos，界面中出现如下的内容，表示集群配置成功</p><h3 id="三-服务提供方"><a href="#三-服务提供方" class="headerlink" title="三. 服务提供方"></a>三. 服务提供方</h3><p><strong>pom.xml 依赖配置</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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-alibaba-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.9.0.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-dependencies<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>Greenwich.SR2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>配置</strong></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line">   <span class="comment"># 服务名</span></span><br><span class="line">   <span class="attr">name:</span> <span class="string">alibaba-provider</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line">   <span class="attr">nacos:</span></span><br><span class="line">     <span class="attr">discovery:</span></span><br><span class="line">       <span class="comment">#必须配置 ip 地址</span></span><br><span class="line">       <span class="attr">server-addr:</span> <span class="number">172.18</span><span class="number">.96</span><span class="number">.177</span><span class="string">:8848,172.18.96.177:9948</span></span><br></pre></td></tr></table></figure><p><strong>启动类</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span>  <span class="comment">//开启 nacos 的服务发现</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProviderApplication</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">       SpringApplication.run(ProviderApplication.class, args);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>服务页面结果</strong></p><h3 id="四-服务消费方"><a href="#四-服务消费方" class="headerlink" title="四. 服务消费方"></a>四. 服务消费方</h3><p><strong>pom.xml 依赖配置</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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-alibaba-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.9.0.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-dependencies<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>Greenwich.SR2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>配置</strong></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8080</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line">   <span class="comment"># 服务名</span></span><br><span class="line">   <span class="attr">name:</span> <span class="string">alibaba-consumer</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line">   <span class="attr">nacos:</span></span><br><span class="line">     <span class="attr">discovery:</span></span><br><span class="line">       <span class="attr">server-addr:</span> <span class="number">172.18</span><span class="number">.96</span><span class="number">.177</span><span class="string">:8848,172.18.96.177:9948</span></span><br><span class="line">       <span class="comment"># 不将自己的服务注册到注册中心</span></span><br><span class="line">       <span class="attr">register-enabled:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure><p><strong>启动类配置</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConsumerApplication</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">       SpringApplication.run(ConsumerApplication.class, args);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>调用服务提供方</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping</span></span><br><span class="line">   <span class="keyword">public</span> Object <span class="title function_">getUsers</span><span class="params">()</span> &#123;</span><br><span class="line">       List&lt;ServiceInstance&gt; list = discoveryClient.getInstances(<span class="string">&quot;alibaba-provider&quot;</span>);</span><br><span class="line">       <span class="type">String</span> <span class="variable">targetUrl</span> <span class="operator">=</span> list.stream().map(si -&gt; si.getUri() + <span class="string">&quot;/user&quot;</span>).findFirst().get();</span><br><span class="line">       List&lt;String&gt; resultList = restTemplate.getForObject(targetUrl, List.class);</span><br><span class="line">       <span class="keyword">return</span> resultList;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="五-Ribbon-负载均衡"><a href="#五-Ribbon-负载均衡" class="headerlink" title="五. Ribbon 负载均衡"></a>五. Ribbon 负载均衡</h3><p>Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具。其主要功能是提供客户端的负载均衡算法，并提供了完善的配置项如连接超时，重试等。简单的说，就是配置文件中列出 Load Balancer 后面所有的机器，Ribbon 会自动的基于某种规则(如简单轮询，随机连接等)去连接这些机器，当然我们也可以使用 Ribbon 自定义负载均衡算法。</p><h4 id="5-1-实现负载均衡"><a href="#5-1-实现负载均衡" class="headerlink" title="5.1 实现负载均衡"></a>5.1 实现负载均衡</h4><p>Ribbon 只是一个客户端的负载均衡器工具，实现起来非常的简单，我们只需要在注入 RestTemplate 的 bean 上加上@LoadBalanced 就可以了。如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> &#123;</span><br><span class="line">   <span class="meta">@LoadBalanced</span></span><br><span class="line">   <span class="meta">@Bean</span></span><br><span class="line">   <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">()</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>();</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="5-2-服务消费方调用"><a href="#5-2-服务消费方调用" class="headerlink" title="5.2 服务消费方调用"></a>5.2 服务消费方调用</h4><p>&#x2F;&#x2F; 直接写上服务名即可<br>List<String> resultList &#x3D; restTemplate.getForObject(“<a href="http://alibaba-provider/user">http://alibaba-provider/user</a>“, List.class);</p><h4 id="5-3-负载均衡策略"><a href="#5-3-负载均衡策略" class="headerlink" title="5.3 负载均衡策略"></a>5.3 负载均衡策略</h4><p>Ribbon 提供了一个很重要的接口叫做 IRule，其中定义了很多的负载均衡策略，默认的是轮询的方式，以下是 Ribbon 的负载均衡策略：</p><table><thead><tr><th>类名</th><th>描述</th></tr></thead><tbody><tr><td>RoundRobbinRule</td><td>轮询</td></tr><tr><td>RandomRule</td><td>随机挑选</td></tr><tr><td>RetryRule</td><td>按照轮询的方式去调用服务，如果其中某个服务不可用，但是还是会尝试几次，如果尝试过几次都没有成功，那么就不在调用该服务，会轮询调用其他的可用服务。</td></tr><tr><td>AvailabilityFilteringRule</td><td>会先过滤掉因为多次访问不可达和并发超过阈值的服务，然后轮询调用其他的服务</td></tr><tr><td>WeightedResponseTimeRule</td><td>根据平均响应时间计算权重，响应越快权重越大，越容易被选中。服务刚重启的时候，还未统计出权重会按照轮询的方式；当统计信息足够的时候，就会按照权重信息访问</td></tr><tr><td>ZoneAvoidanceRule</td><td>判断 server 所在的区域性能和可用性选择服务器</td></tr><tr><td>BestAvailableRule</td><td>会过滤掉多次访问都不可达的服务，然后选择并发量最小的服务进行调用，默认方式</td></tr></tbody></table><p>改变 Ribbon 的负责均衡策略：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> IRule <span class="title function_">getRule</span><span class="params">()</span> &#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RandomRule</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="5-4-自定义负载均衡策略"><a href="#5-4-自定义负载均衡策略" class="headerlink" title="5.4 自定义负载均衡策略"></a>5.4 自定义负载均衡策略</h4><p>我们自定义的负载均衡策略需要继承 AbstractLoadBalancerRule 这个类，然后重写 choose 方法，然后将其注入到容器中，如下所示：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Customize_Rule</span> <span class="keyword">extends</span> <span class="title class_">AbstractLoadBalancerRule</span> &#123;</span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">Logger</span> <span class="variable">logger</span> <span class="operator">=</span> LoggerFactory.getLogger(Customize_Rule.class);</span><br><span class="line">   <span class="keyword">private</span> <span class="type">int</span> <span class="variable">currentIndex</span> <span class="operator">=</span> <span class="number">0</span>; <span class="comment">//当前调用的索引</span></span><br><span class="line">   <span class="keyword">private</span> <span class="type">int</span> <span class="variable">num</span> <span class="operator">=</span> <span class="number">1</span>; <span class="comment">//次数</span></span><br><span class="line">   <span class="keyword">private</span> <span class="type">int</span> <span class="variable">limit</span> <span class="operator">=</span> <span class="number">5</span>;</span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 初始化工作</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> iClientConfig</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">initWithNiwsConfig</span><span class="params">(IClientConfig iClientConfig)</span> &#123;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> Server <span class="title function_">choose</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">       <span class="type">ILoadBalancer</span> <span class="variable">balancer</span> <span class="operator">=</span> getLoadBalancer();</span><br><span class="line">       <span class="keyword">return</span> choose(balancer, key);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">private</span> Server <span class="title function_">choose</span><span class="params">(ILoadBalancer balancer, Object key)</span> &#123;</span><br><span class="line">       <span class="type">Server</span> <span class="variable">server</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">       <span class="keyword">while</span>(<span class="literal">null</span> == server) &#123;</span><br><span class="line">           <span class="comment">//获取所有可用的服务</span></span><br><span class="line">           List&lt;Server&gt; reachableServers = balancer.getReachableServers();</span><br><span class="line">           <span class="keyword">if</span> (<span class="number">0</span> == reachableServers.size()) &#123;</span><br><span class="line">               logger.error(<span class="string">&quot;没有可用的服务&quot;</span>);</span><br><span class="line">               <span class="keyword">return</span> <span class="literal">null</span>;  <span class="comment">//退出 while 循环</span></span><br><span class="line">           &#125;</span><br><span class="line">           <span class="type">int</span> <span class="variable">total</span> <span class="operator">=</span> reachableServers.size(); <span class="comment">//可用服务的数量</span></span><br><span class="line">           <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">               <span class="comment">/**</span></span><br><span class="line"><span class="comment">                * 有种极端情况，当我们在使用最后一个服务的时候，其他的服务都不可用，可能导致索引越界异常</span></span><br><span class="line"><span class="comment">                */</span></span><br><span class="line">               <span class="keyword">if</span> (currentIndex + <span class="number">1</span> &gt; total) &#123;</span><br><span class="line">                   currentIndex = <span class="number">0</span>;</span><br><span class="line">                   server = reachableServers.get(currentIndex);  <span class="comment">//获取第一个服务</span></span><br><span class="line">                   num = <span class="number">0</span>;</span><br><span class="line">                   num++;</span><br><span class="line">               &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                   <span class="keyword">if</span>(limit == num) &#123;</span><br><span class="line">                       currentIndex++;</span><br><span class="line">                       num = <span class="number">0</span>;</span><br><span class="line">                       <span class="keyword">if</span>(currentIndex == total) &#123;</span><br><span class="line">                           currentIndex=<span class="number">0</span>;</span><br><span class="line">                           server = reachableServers.get(currentIndex);  <span class="comment">//获取第一个服务</span></span><br><span class="line">                           num++;</span><br><span class="line">                       &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                           server = reachableServers.get(currentIndex);</span><br><span class="line">                           num++;</span><br><span class="line">                       &#125;</span><br><span class="line">                   &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                       server = reachableServers.get(currentIndex);</span><br><span class="line">                       num++;</span><br><span class="line">                   &#125;</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> server;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将其注入到容器中，方式如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> IRule <span class="title function_">getRule</span><span class="params">()</span> &#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Customize_Rule</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="六-Feign-负载均衡"><a href="#六-Feign-负载均衡" class="headerlink" title="六. Feign 负载均衡"></a>六. Feign 负载均衡</h3><p>feign 是基于 Ribbon 的另外一个负载均衡的客户端框架，只需要在接口上定义要调用的服务名即可，使用起来非常的简单。<br><strong>pom.xml 依赖</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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>启动类配置</strong><br>需要在启动类上加上@EnableFeignClients 这个注解</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConsumerApplication</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">       SpringApplication.run(ConsumerApplication.class, args);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>服务接口配置</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@FeignClient(name=&quot;alibaba-provider&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserService</span> &#123;</span><br><span class="line">   <span class="meta">@RequestMapping(&quot;/user&quot;)</span></span><br><span class="line">   <span class="keyword">public</span> List&lt;String&gt; <span class="title function_">getUsers</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="七-熔断与服务降级"><a href="#七-熔断与服务降级" class="headerlink" title="七. 熔断与服务降级"></a>七. 熔断与服务降级</h3><p>分布式系统中一个微服务需要依赖于很多的其他的服务，那么服务就会不可避免的失败。例如 A 服务依赖于 B、C、D 等很多的服务，当 B 服务不可用的时候，会一直阻塞或者异常，更不会去调用 C 服务和 D 服务。同时假设有其他的服务也依赖于 B 服务，也会碰到同样的问题，这就及有可能导致雪崩效应。<br>如下案例：一个用户通过通过 web 容器访问应用，他要先后调用 A、H、I、P 四个模块，一切看着都很美好。</p><p>由于某些原因，导致 I 服务不可用，与此同时我们没有快速处理，会导致该用户一直处于阻塞状态。</p><p>当其他用户做同样的请求，也会面临着同样的问题，tomcat 支持的最大并发数是有限的，资源都是有限的，将整个服务器拖垮都是有可能的。</p><p>Sentinel 是一个用于分布式系统的延迟和容错的开源库，在分布式系统中，许多依赖会不可避免的调用失败，例如超时，异常等，Hystrix 能保证在一个依赖出现问题的情况下，不会导致整体服务失败，避免级联故障，以提高分布式系统的弹性。<br>断路器本身是一种开关装置，当某个服务单元发生故障后，通过断路器的故障监控（类似于保险丝），向调用者返回符合预期的，可处理的备选响应，而不是长时间的等待或者抛出无法处理的异常，这样就保证了服务调用的线程不会被长时间，不必要的占用，从而避免故障在分布式系统中的蔓延，乃至雪崩。<br>Sentinel 在网络依赖服务出现高延迟或者失败时，为系统提供保护和控制;可以进行快速失败，缩短延迟等待时间；提供失败回退（Fallback）和相对优雅的服务降级机制；提供有效的服务容错监控、报警和运维控制手段。<br>下载地址：<a href="https://github.com/alibaba/Sentinel/releases">https://github.com/alibaba/Sentinel/releases</a></p><h4 id="7-1-依赖"><a href="#7-1-依赖" class="headerlink" title="7.1 依赖"></a>7.1 依赖</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-sentinel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="7-2-配置"><a href="#7-2-配置" class="headerlink" title="7.2 配置"></a>7.2 配置</h4><p>通常情况下我们只需要在服务提供方实现熔断或者服务降级即可，但是如果要相对服务消费方是实现限流，在服务的提供方和消费方都需要加如下配置。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">sentinel:</span></span><br><span class="line">     <span class="attr">transport:</span></span><br><span class="line">       <span class="comment"># sentinel 控制台的地址</span></span><br><span class="line">       <span class="attr">dashboard:</span> <span class="string">localhost:8080</span></span><br><span class="line">     <span class="comment"># 立即加载</span></span><br><span class="line">     <span class="attr">eager:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="7-3-sentinel-的控制面板"><a href="#7-3-sentinel-的控制面板" class="headerlink" title="7.3 sentinel 的控制面板"></a>7.3 sentinel 的控制面板</h4><p>在浏览器输入 localhost:8080，使用 sentinel&#x2F;sentinel 来访问 sentinel 的控制面板：</p><p>接下来对 sentinel 的控制面板一一讲解：<br><strong>实时监控</strong><br>用于查看接口调用的 QPS(Query Per Second)以及平均响应时间。<br><strong>簇点链路</strong><br>查看当前追踪的所有的访问接口，可以添加<code>流量规则</code>、<code>降级规则</code>、<code>热点规则</code>、<code>授权规则</code>。<br><strong>流量规则</strong></p><p>**资源名：**是需要控制的链路的名字，例如&#x2F;student&#x2F;all 等<br><strong>针对来源:</strong> 默认为 default 表示所有，也可以针对特定的服务进行设置。<br><strong>阈值类型:</strong> 是指如何进行限制，可以是 QPS，也可以是线程。<br><strong>单机阈值:</strong> 是控制 QPS 或者线程的数量。<br><strong>流量模式:</strong> 直接表示只是针对指定资源进行限制；关联是指当被关联的资源达到阈值时候，指定资源被限制访问；链路是更加细粒度的控制，控制指定资源对链路的限制。<br><strong>流控效果:</strong> 快速失败是指，当无法访问的时候立即给用户一个错误响应；Warm Up(预热)是指经过指定的时间后才达到指定的阈值(sentinel 内有值为 <code>coldFactor</code> 为 3，即请求 QPS 从 <code>threshold / 3</code> 开始，经预热时长逐渐升至设定的 QPS 阈值，参考地址：<a href="https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8">https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8</a>)；排队等待只是匀速的通过(每秒指定的 QPS)，其他的请求进行排队，但是并不会一直排下去，超过指定的时间就会失败，阈值类型必须设置为 QPS，不能为线程。<br><strong>降级规则</strong></p><p><strong>资源名:</strong> 要实现降级的资源。<br><strong>降级策略:</strong></p><ol><li>RT(平均响应时间)</li></ol><p>如果在一秒钟之内进入的请求的平均响应时间小于 1ms，那么在未来 5s 钟之内所有的请求都会熔断降级。 2) 异常比例<br>如果在一秒钟之内的请求数异常比例大于指定的数据，那么在未来的时间窗口内会一直熔断降级。统计单位为 s. 3) 异常数<br>如果在一分钟之内，异常数量大于指定的值，那么在指定的时间窗口内请求一直会熔断降级，注意时间窗口的值一般设置要大于 60，因为设置如果小于 60，可能会一直处于熔断状态。<br><strong>热点规则</strong><br>热点规则是针对具体的请求参数进行设置，例如如下的方法：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/edit&quot;)</span></span><br><span class="line"><span class="meta">@SentinelResource(&quot;edit&quot;)</span>   <span class="comment">//必须的有</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">edit</span><span class="params">(<span class="meta">@RequestParam(required = false)</span> String id,</span></span><br><span class="line"><span class="params">                  <span class="meta">@RequestParam(required = false)</span> Integer age)</span> &#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="built_in">this</span>.studentService.commons();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>资源名:</strong> 是@SentinelResource 中设置的值<br><strong>参数索引:</strong> 对那个参数进行 QPS 限制，通过索引来指定。<br>**单机阈值：**指定在统计时长内的阈值。<br>**统计窗口时长: **统计的 QPS 的时间。<br><strong>系统规则</strong></p><p><strong>LOAD:</strong> 仅对 Linux&#x2F;Unix-like 机器生效，参考值一般是 <code>CPU cores * 2.5</code><br>**RT: **当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护，单位是毫秒。<br>**线程数: **当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。<br><strong>入口 QPS:</strong> 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。<br><strong>授权规则</strong><br>授权规则是指可以将特定的访问应用加入黑名单或者白名单，但是必须在访问的时候携带应用的名称。代码实现部分如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SentinelOriginParser</span> <span class="keyword">implements</span> <span class="title class_">RequestOriginParser</span> &#123;</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> String <span class="title function_">parseOrigin</span><span class="params">(HttpServletRequest httpServletRequest)</span> &#123;</span><br><span class="line">       <span class="type">String</span> <span class="variable">origin</span> <span class="operator">=</span> httpServletRequest.getParameter(<span class="string">&quot;origin&quot;</span>);</span><br><span class="line">       <span class="keyword">if</span>(StringUtil.isBlank(origin)) &#123;</span><br><span class="line">           <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;origin parameter must be specified.&quot;</span>);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> origin;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>加上了来源解析后，在往后的访问中必须要携带 origin 参数，在 sentinel 的 dashboard 中可以作如下配置：</p><p><strong>集群流控</strong></p><p>**是否集群: **是否采用集群<br><strong>均摊阈值:</strong> 就是每个集群节点每秒的 QPS.<br>**集群阈值模式: **单机均摊是集群中每个节点每秒的 QPS, 总体阈值是整个集群每秒的 QPS.<br><strong>集群流控</strong></p><h4 id="7-4-SentinelResource"><a href="#7-4-SentinelResource" class="headerlink" title="7.4 @SentinelResource"></a>7.4 @SentinelResource</h4><p>@SentinelResource 是 sentinel 中非常重要的注解，提供了简单易用的功能。其中 blockHandler 注解是限流的处理方法，fallback 是服务降级的处理方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SentinelResource(value=&quot;edit&quot;, blockHandler=&quot;editBlock&quot;, fallback = &quot;editFallback&quot;)</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/edit&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">edit</span><span class="params">(<span class="meta">@RequestParam(required = false)</span> String id,</span></span><br><span class="line"><span class="params">                  <span class="meta">@RequestParam(required = false)</span> Integer age)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">   Thread.sleep(<span class="number">20</span>);</span><br><span class="line">   <span class="keyword">return</span> <span class="built_in">this</span>.studentService.commons();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 限流的处理</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">editBlock</span><span class="params">(String id, Integer age, BlockException ex)</span> &#123;</span><br><span class="line">   Map&lt;String, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">   map.put(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;限流了.&quot;</span>);</span><br><span class="line">   <span class="keyword">return</span> map;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//服务降级的处理方法</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">editFallback</span><span class="params">(String id, Integer age)</span> &#123;</span><br><span class="line">   Map&lt;String, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">   map.put(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;fallback 服务降级了.&quot;</span>);</span><br><span class="line">   <span class="keyword">return</span> map;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="八-Feign-与-Sentinel-的整合"><a href="#八-Feign-与-Sentinel-的整合" class="headerlink" title="八. Feign 与 Sentinel 的整合"></a>八. Feign 与 Sentinel 的整合</h3><p><strong>配置</strong></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">feign:</span></span><br><span class="line"> <span class="attr">sentinel:</span></span><br><span class="line">   <span class="comment"># 默认是没有提示的</span></span><br><span class="line">   <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="8-1-服务降级后的处理"><a href="#8-1-服务降级后的处理" class="headerlink" title="8.1 服务降级后的处理"></a>8.1 服务降级后的处理</h4><p>可以在@FeignClient 中配置 fallback，来指定服务降级后给用户返回的什么样的数据，fallback 的值为 Class 类型的对象，该类必须要实现该对应的接口。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@FeignClient(name=&quot;alibaba-provider&quot;, fallback = UserServiceFallback.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserService</span> &#123;</span><br><span class="line">   <span class="meta">@RequestMapping(&quot;/user&quot;)</span></span><br><span class="line">   <span class="keyword">public</span> List&lt;String&gt; <span class="title function_">getUsers</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line">UserServiceFallback 的实现如下：</span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserServiceFallback</span> <span class="keyword">implements</span> <span class="title class_">UserService</span> &#123;</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> List&lt;String&gt; <span class="title function_">getUsers</span><span class="params">()</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> Arrays.asList(<span class="string">&quot;服务降级了, 这是降级后返回的信息.&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="8-2-服务降级的异常处理"><a href="#8-2-服务降级的异常处理" class="headerlink" title="8.2 服务降级的异常处理"></a>8.2 服务降级的异常处理</h4><p>对于 fallback 来讲，并不能追踪到异常信息，在实际的业务处理过程中，我们往往需要记录异常的信息，那么就要使用 fallbackFactory 属性来实现。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserServiceFallbackFactory</span> <span class="keyword">implements</span> <span class="title class_">FallbackFactory</span>&lt;UserService&gt; &#123;</span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">Logger</span> <span class="variable">logger</span> <span class="operator">=</span> LoggerFactory.getLogger(UserServiceFallbackFactory.class);</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> UserService <span class="title function_">create</span><span class="params">(Throwable cause)</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UserService</span>() &#123;</span><br><span class="line">           <span class="meta">@Override</span></span><br><span class="line">           <span class="keyword">public</span> List&lt;String&gt; <span class="title function_">getUsers</span><span class="params">()</span> &#123;</span><br><span class="line">               logger.info(cause.getMessage());</span><br><span class="line">               <span class="keyword">return</span> Arrays.asList(<span class="string">&quot;服务降级的方法&quot;</span>);</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="九-Sentinel-的持久化"><a href="#九-Sentinel-的持久化" class="headerlink" title="九. Sentinel 的持久化"></a>九. Sentinel 的持久化</h3><p>通过接入 Sentinel Dashboard 后，在页面上操作来更新规则，都无法避免一个问题，那就是服务重新后，规则就丢失了，因为默认情况下规则是保存在内存中的。sentinel 中持久化的方式有两种，pull 模式和 push 模式。<br>pull 模式是指站在第三方持久化系统(redis, nacos)的角度，他们去到 sentinel 中定时去拉去配置信息，可能会造成数据的不一致性。<br>push 模式是站在 sentinel 的角度，将其配置信息主动推送给第三方持久化系统，sentinel 官方也推荐在线上使用该模式。</p><h4 id="9-1-sentinel-dashboard-改造"><a href="#9-1-sentinel-dashboard-改造" class="headerlink" title="9.1 sentinel-dashboard 改造"></a>9.1 sentinel-dashboard 改造</h4><p>A. 将 sentinel 的源码 clone 到本地<br>B. 进入到 sentinel-dashboard 目录下，修改 pom.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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.csp<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>sentinel-datasource-nacos<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><!-- 修改之后的内容 --><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.csp<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>sentinel-datasource-nacos<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p>C. 修改 src\main\webapp\resources\app\scripts\directives\sidebar\sidebar.html 文件<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- &lt;li ui-sref-active=&quot;active&quot; ng-if=&quot;entry.appType==0&quot;&gt;  --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- &lt;a ui-sref=&quot;dashboard.flow(&#123;app: entry.app&#125;)&quot;&gt;  --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- &lt;i class=&quot;glyphicon glyphicon-filter&quot;&gt;&lt;/i&gt;  流控规则 V1&lt;/a&gt;  --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- &lt;/li&gt; --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">li</span> <span class="attr">ui-sref-active</span>=<span class="string">&quot;active&quot;</span> <span class="attr">ng-if</span>=<span class="string">&quot;!entry.isGateway&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">a</span> <span class="attr">ui-sref</span>=<span class="string">&quot;dashboard.flowV1(&#123;app: entry.app&#125;)&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">&quot;glyphicon glyphicon-filter&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span>  流控规则</span><br><span class="line">    <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">li</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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">li</span> <span class="attr">ui-sref-active</span>=<span class="string">&quot;active&quot;</span> <span class="attr">ng-if</span>=<span class="string">&quot;entry.appType==0&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">a</span> <span class="attr">ui-sref</span>=<span class="string">&quot;dashboard.flow(&#123;app: entry.app&#125;)&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">&quot;glyphicon glyphicon-filter&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span>  流控规则</span><br><span class="line">    <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--   &lt;li ui-sref-active=&quot;active&quot; ng-if=&quot;!entry.isGateway&quot;&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--       &lt;a ui-sref=&quot;dashboard.flow(&#123;app: entry.app&#125;)&quot;&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--            &lt;i class=&quot;glyphicon glyphicon-filter&quot;&gt;&lt;/i&gt;  流控规则</span></span><br><span class="line"><span class="comment">           &lt;/a&gt;   --&gt;</span></span><br><span class="line"><span class="comment">&lt;!--    &lt;/li&gt;--&gt;</span></span><br></pre></td></tr></table></figure><p>D. 将 <code>src\test\java\com\alibaba\csp\sentinel\dashboard\rule\nacos</code> 目录下的四个Java文件拷贝到<code>src\main\java\com\alibaba\csp\sentinel\dashboard\rule</code> 目录下</p><p>E. 修改 <code>src\main\webapp\resources\app\scripts\controllers\identity.js</code> 文件，修改内容如下：</p><p>F. 重新打包生成 Jar 包，进入到 sentinel 目录下(<strong>注：不是 sentinel-dashboard 目录</strong>)，执行如下命令：<br>mvn clean                <br>mvn install -DskipTests<br>G. 进入到 sentinel-dashboard&#x2F;target 目录下，执行如下内容：<br>java -jar sentinel-dashboard.jar</p><h4 id="9-2-配置"><a href="#9-2-配置" class="headerlink" title="9.2 配置"></a>9.2 配置</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line">   <span class="attr">sentinel:</span></span><br><span class="line">     <span class="attr">datasource:</span></span><br><span class="line">       <span class="comment"># 这个名字随意，但是要有意义</span></span><br><span class="line">       <span class="attr">flow:</span></span><br><span class="line">         <span class="attr">nacos:</span></span><br><span class="line">           <span class="attr">server-addr:</span> <span class="number">192.168</span><span class="number">.31</span><span class="number">.173</span><span class="string">:8848</span></span><br><span class="line">           <span class="attr">groupId:</span> <span class="string">SENTINEL_GROUP</span></span><br><span class="line">           <span class="attr">rule-type:</span> <span class="string">flow</span></span><br></pre></td></tr></table></figure><h4 id="9-3-测试"><a href="#9-3-测试" class="headerlink" title="9.3 测试"></a>9.3 测试</h4><p>在 sentinel-dashboard 控制面板添加一个流量控制规则</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件，方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。&lt;br&gt;依托 Spring Cloud Alibaba，您只需要添加一些注解和少量配置，就可以将 Spring Cloud 应用接入阿里微服务解决方案，通过阿里中间件来迅速搭建分布式应用系统。&lt;/p&gt;</summary>
    
    
    
    <category term="Spring Cloud Alibaba" scheme="http://next.skyheng.com/categories/Spring-Cloud-Alibaba/"/>
    
    
    <category term="Spring Cloud Alibaba" scheme="http://next.skyheng.com/tags/Spring-Cloud-Alibaba/"/>
    
  </entry>
  
  <entry>
    <title>Spring Gateway 跨域请求头重复处理过滤器</title>
    <link href="http://next.skyheng.com/post/48790.html"/>
    <id>http://next.skyheng.com/post/48790.html</id>
    <published>2020-09-05T16:35:22.000Z</published>
    <updated>2025-11-30T14:41:25.916Z</updated>
    
    <content type="html"><![CDATA[<p>Spring Gateway 跨域请求头重复处理过滤器</p><span id="more"></span><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CorsResponseHeaderFilter</span> <span class="keyword">implements</span> <span class="title class_">GlobalFilter</span>, Ordered &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 指定位于 NettyWriteResponseFilter 处理完响应体后移除重复 CORS 响应头</span></span><br><span class="line">        <span class="keyword">return</span> NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;serial&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Mono&lt;Void&gt; <span class="title function_">filter</span><span class="params">(ServerWebExchange exchange, GatewayFilterChain chain)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> chain.filter(exchange).then(Mono.defer(() -&gt; &#123;</span><br><span class="line">            exchange.getResponse().getHeaders().entrySet().stream()</span><br><span class="line">                    .filter(kv -&gt; (kv.getValue() != <span class="literal">null</span> &amp;&amp; kv.getValue().size() &gt; <span class="number">1</span>))</span><br><span class="line">                    .filter(kv -&gt; (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)</span><br><span class="line">                            || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)))</span><br><span class="line">                    .forEach(kv -&gt; kv.setValue(<span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;String&gt;() &#123;&#123;</span><br><span class="line">                        add(kv.getValue().get(<span class="number">0</span>));</span><br><span class="line">                    &#125;&#125;));</span><br><span class="line">            <span class="keyword">return</span> chain.filter(exchange);</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>]]></content>
    
    
    <summary type="html">&lt;p&gt;Spring Gateway 跨域请求头重复处理过滤器&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Spring Cloud升级之路-loadbalancer</title>
    <link href="http://next.skyheng.com/post/4579.html"/>
    <id>http://next.skyheng.com/post/4579.html</id>
    <published>2020-09-05T15:47:22.000Z</published>
    <updated>2025-11-30T14:41:25.915Z</updated>
    
    <content type="html"><![CDATA[<p>Spring Cloud升级之路-loadbalancer</p><span id="more"></span><h2 id="Hoxton-3-负载均衡从-ribbon-替换成-spring-cloud-loadbalancer"><a href="#Hoxton-3-负载均衡从-ribbon-替换成-spring-cloud-loadbalancer" class="headerlink" title="Hoxton - 3. 负载均衡从 ribbon 替换成 spring-cloud-loadbalancer"></a>Hoxton - 3. 负载均衡从 ribbon 替换成 spring-cloud-loadbalancer</h2><h2 id="负载均衡-Ribbon-替换成-Spring-Cloud-Load-Balancer"><a href="#负载均衡-Ribbon-替换成-Spring-Cloud-Load-Balancer" class="headerlink" title="负载均衡 Ribbon 替换成 Spring Cloud Load Balancer"></a>负载均衡 Ribbon 替换成 Spring Cloud Load Balancer</h2><p><code>Spring Cloud Load Balancer</code>并不是一个独立的项目，而是<code>spring-cloud-commons</code>其中的一个模块。 项目中用了<code>Eureka</code>以及相关的 starter，想完全剔除<code>Ribbon</code>的相关依赖基本是不可能的，Spring 社区的人也是看到了这一点，通过配置去关闭<code>Ribbon</code>启用<code>Spring-Cloud-LoadBalancer</code>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">spring.cloud.loadbalancer.ribbon.enabled=false</span><br></pre></td></tr></table></figure><p>关闭 ribbon 之后，Spring Cloud LoadBalancer 就会加载成为默认的负载均衡器。<br>Spring Cloud LoadBalancer 结构如下所示：</p><p>其中：</p><ol><li>全局只有一个 <code>BlockingLoadBalancerClient</code>，负责执行所有的负载均衡请求。</li><li><code>BlockingLoadBalancerClient</code>从<code>LoadBalancerClientFactory</code>里面加载对应微服务的负载均衡配置。</li><li>每个微服务下有独自的<code>LoadBalancer</code>，<code>LoadBalancer</code>里面包含负载均衡的算法，例如<code>RoundRobin</code>.根据算法，从<code>ServiceInstanceListSupplier</code>返回的实例列表中选择一个实例返回。</li></ol><h3 id="1-实现zone隔离"><a href="#1-实现zone隔离" class="headerlink" title="1. 实现zone隔离"></a>1. 实现<code>zone</code>隔离</h3><p>要想实现<code>zone</code>隔离，应该从<code>ServiceInstanceListSupplier</code>里面做手脚。默认的实现里面有关于<code>zone</code>隔离的<code>ServiceInstanceListSupplier</code> -&gt; <code>org.springframework.cloud.loadbalancer.core.ZonePreferenceServiceInstanceListSupplier</code>:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> List&lt;ServiceInstance&gt; <span class="title function_">filteredByZone</span><span class="params">(List&lt;ServiceInstance&gt; serviceInstances)</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (zone == <span class="literal">null</span>) &#123;</span><br><span class="line">zone = zoneConfig.getZone();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//如果zone不为null，并且该zone下有存活实例，则返回这个实例列表</span></span><br><span class="line"><span class="comment">//否则，返回所有的实例</span></span><br><span class="line"><span class="keyword">if</span> (zone != <span class="literal">null</span>) &#123;</span><br><span class="line">List&lt;ServiceInstance&gt; filteredInstances = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"><span class="keyword">for</span> (ServiceInstance serviceInstance : serviceInstances) &#123;</span><br><span class="line"><span class="type">String</span> <span class="variable">instanceZone</span> <span class="operator">=</span> getZone(serviceInstance);</span><br><span class="line"><span class="keyword">if</span> (zone.equalsIgnoreCase(instanceZone)) &#123;</span><br><span class="line">filteredInstances.add(serviceInstance);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (filteredInstances.size() &gt; <span class="number">0</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> filteredInstances;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// If the zone is not set or there are no zone-specific instances available,</span></span><br><span class="line"><span class="comment">// we return all instances retrieved for given service id.</span></span><br><span class="line"><span class="keyword">return</span> serviceInstances;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里对于没指定<code>zone</code>或者该<code>zone</code>下没有存活实例的情况下，会返回所有查到的实例，不区分<code>zone</code>。这个不符合我们的要求，所以我们修改并实现下我们自己的<a href="https://github.com/HashZhang/spring-cloud-scaffold/blob/master/spring-cloud-hoxton/spring-cloud-hoxton-service-consumer/src/main/java/com/github/hashjang/hoxton/service/consumer/config/SameZoneOnlyServiceInstanceListSupplier.java">com.github.hashjang.hoxton.service.consumer.config.SameZoneOnlyServiceInstanceListSupplier</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><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> List&lt;ServiceInstance&gt; <span class="title function_">filteredByZone</span><span class="params">(List&lt;ServiceInstance&gt; serviceInstances)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (zone == <span class="literal">null</span>) &#123;</span><br><span class="line">        zone = zoneConfig.getZone();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (zone != <span class="literal">null</span>) &#123;</span><br><span class="line">        List&lt;ServiceInstance&gt; filteredInstances = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (ServiceInstance serviceInstance : serviceInstances) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">instanceZone</span> <span class="operator">=</span> getZone(serviceInstance);</span><br><span class="line">            <span class="keyword">if</span> (zone.equalsIgnoreCase(instanceZone)) &#123;</span><br><span class="line">                filteredInstances.add(serviceInstance);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (filteredInstances.size() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> filteredInstances;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//如果没找到就返回空列表，绝不返回其他集群的实例</span></span><br><span class="line">    <span class="keyword">return</span> List.of();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后我们来看一下默认的 <code>Spring Cloud LoadBalancer</code> 提供的 <code>LoadBalancer</code> ，它是带缓存的：<br><code>org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@ConditionalOnBean(ReactiveDiscoveryClient.class)</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean</span></span><br><span class="line"><span class="keyword">public</span> ServiceInstanceListSupplier <span class="title function_">discoveryClientServiceInstanceListSupplier</span><span class="params">(</span></span><br><span class="line"><span class="params">ReactiveDiscoveryClient discoveryClient, Environment env,</span></span><br><span class="line"><span class="params">ApplicationContext context)</span> &#123;</span><br><span class="line"><span class="type">DiscoveryClientServiceInstanceListSupplier</span> <span class="variable">delegate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DiscoveryClientServiceInstanceListSupplier</span>(</span><br><span class="line">discoveryClient, env);</span><br><span class="line">ObjectProvider&lt;LoadBalancerCacheManager&gt; cacheManagerProvider = context</span><br><span class="line">.getBeanProvider(LoadBalancerCacheManager.class);</span><br><span class="line"><span class="keyword">if</span> (cacheManagerProvider.getIfAvailable() != <span class="literal">null</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CachingServiceInstanceListSupplier</span>(delegate,</span><br><span class="line">cacheManagerProvider.getIfAvailable());</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> delegate;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>DiscoveryClientServiceInstanceListSupplier</code>每次从<code>Eureka</code>上面拉取实例列表，<code>CachingServiceInstanceListSupplier</code>提供了缓存，这样不必每次从<code>Eureka</code>上面拉取。可以看出<code>CachingServiceInstanceListSupplier</code>是一种代理模式的实现，和<code>SameZoneOnlyServiceInstanceListSupplier</code>的模式是一样的。<br>我们来组装我们的<code>ServiceInstanceListSupplier</code>，由于我们是同步的环境，只用实现同步的<code>ServiceInstanceListSupplier</code>就行了。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CommonLoadBalancerConfig</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 同步环境下的ServiceInstanceListSupplier</span></span><br><span class="line"><span class="comment">     * SameZoneOnlyServiceInstanceListSupplier限制仅返回同一个zone下的实例（注意）</span></span><br><span class="line"><span class="comment">     * CachingServiceInstanceListSupplier启用缓存，不每次访问eureka请求实例列表</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> discoveryClient</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> env</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> zoneConfig</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@Order(Integer.MIN_VALUE)</span></span><br><span class="line">    <span class="keyword">public</span> ServiceInstanceListSupplier <span class="title function_">discoveryClientServiceInstanceListSupplier</span><span class="params">(</span></span><br><span class="line"><span class="params">            DiscoveryClient discoveryClient, Environment env,</span></span><br><span class="line"><span class="params">            LoadBalancerZoneConfig zoneConfig,</span></span><br><span class="line"><span class="params">            ApplicationContext context)</span> &#123;</span><br><span class="line">        <span class="type">ServiceInstanceListSupplier</span> <span class="variable">delegate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SameZoneOnlyServiceInstanceListSupplier</span>(</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">DiscoveryClientServiceInstanceListSupplier</span>(discoveryClient, env),</span><br><span class="line">                zoneConfig</span><br><span class="line">        );</span><br><span class="line">        ObjectProvider&lt;LoadBalancerCacheManager&gt; cacheManagerProvider = context</span><br><span class="line">                .getBeanProvider(LoadBalancerCacheManager.class);</span><br><span class="line">        <span class="keyword">if</span> (cacheManagerProvider.getIfAvailable() != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CachingServiceInstanceListSupplier</span>(</span><br><span class="line">                    delegate,</span><br><span class="line">                    cacheManagerProvider.getIfAvailable()</span><br><span class="line">            );</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> delegate;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2-实现下一次重试的时候，如果存在其他实例，则一定会重试与本次不同的其他实例"><a href="#2-实现下一次重试的时候，如果存在其他实例，则一定会重试与本次不同的其他实例" class="headerlink" title="2. 实现下一次重试的时候，如果存在其他实例，则一定会重试与本次不同的其他实例"></a>2. 实现下一次重试的时候，如果存在其他实例，则一定会重试与本次不同的其他实例</h3><p>默认的<code>RoundRobinLoadBalancer</code>，其中的轮询<code>position</code>，是一个<code>Atomic</code>类型的，在某个微服务的调用请求下，所有线程，所有请求共用（调用其他的每个微服务会创建一个<code>RoundRobinLoadBalancer</code>）。在使用的时候，会有这样的一个问题：</p><ul><li>假设某个微服务有两个实例，实例 A 和实例 B</li><li>某次请求 X 发往实例 A，position &#x3D; position + 1</li><li>在请求没有返回时，请求 Y 到达，发往实例 B，position &#x3D; position + 1</li><li>请求 A 失败，重试，重试的实例还是实例 A</li></ul><p>这样在重试的情况下，某个请求的重试可能会发送到上一次的实例进行重试，这不是我们想要的。针对这个，我提了个 Issue：<a href="https://github.com/spring-cloud/spring-cloud-commons/issues/747">Enhance RoundRoubinLoadBalancer position</a>。我修改的思路是，我们需要一个单次请求隔离的<code>position</code>，这个<code>position</code>对于实例个数取余得出请求要发往的实例。那么如何进行请求隔离呢？<br>首先想到的是线程隔离，但是这个是不行的。Spring Cloud LoadBalancer 底层运用了 reactor 框架，导致实际承载选择实例的线程，不是业务线程，而是 reactor 里面的线程池，如图所示：<br>所以，不能用<code>ThreadLocal</code>的方式实现<code>position</code>。<br>由于我们用到了<code>sleuth</code>，一般请求的<code>context</code>会传递其中的<code>traceId</code>，我们根据这个<code>traceId</code>区分不同的请求，实现我们的 <code>LoadBalancer</code>：<br><a href="https://github.com/HashZhang/spring-cloud-scaffold/blob/master/spring-cloud-hoxton/spring-cloud-hoxton-service-consumer/src/main/java/com/github/hashjang/hoxton/service/consumer/config/RoundRobinBaseOnTraceIdLoadBalancer.java"><code>RoundRobinBaseOnTraceIdLoadBalancer</code></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><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//这个超时时间，需要设置的比你的请求的 connectTimeout + readTimeout 长</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> LoadingCache&lt;Long, AtomicInteger&gt; positionCache = Caffeine.newBuilder().expireAfterWrite(<span class="number">3</span>, TimeUnit.SECONDS).build(k -&gt; <span class="keyword">new</span> <span class="title class_">AtomicInteger</span>(ThreadLocalRandom.current().nextInt(<span class="number">0</span>, <span class="number">1000</span>)));</span><br><span class="line"><span class="keyword">private</span> Response&lt;ServiceInstance&gt; <span class="title function_">getInstanceResponse</span><span class="params">(List&lt;ServiceInstance&gt; serviceInstances)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (serviceInstances.isEmpty()) &#123;</span><br><span class="line">        log.warn(<span class="string">&quot;No servers available for service: &quot;</span> + <span class="built_in">this</span>.serviceId);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">EmptyResponse</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//如果没有 traceId，就生成一个新的，但是最好检查下为啥会没有</span></span><br><span class="line">    <span class="comment">//是不是 MQ 消费这种没有主动生成 traceId 的情况，最好主动生成下。</span></span><br><span class="line">    <span class="type">Span</span> <span class="variable">currentSpan</span> <span class="operator">=</span> tracer.currentSpan();</span><br><span class="line">    <span class="keyword">if</span> (currentSpan == <span class="literal">null</span>) &#123;</span><br><span class="line">        currentSpan = tracer.newTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">long</span> <span class="variable">l</span> <span class="operator">=</span> currentSpan.context().traceId();</span><br><span class="line">    <span class="type">int</span> <span class="variable">seed</span> <span class="operator">=</span> positionCache.get(l).getAndIncrement();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DefaultResponse</span>(serviceInstances.get(seed % serviceInstances.size()));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-替换默认的负载均衡相关-Bean-实现"><a href="#3-替换默认的负载均衡相关-Bean-实现" class="headerlink" title="3. 替换默认的负载均衡相关 Bean 实现"></a>3. 替换默认的负载均衡相关 Bean 实现</h3><p>我们要用上面的两个类替换默认的实现，先编写一个配置类：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CommonLoadBalancerConfig</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="type">boolean</span> <span class="variable">isValid</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 同步环境下的ServiceInstanceListSupplier</span></span><br><span class="line"><span class="comment">     * SameZoneOnlyServiceInstanceListSupplier限制仅返回同一个zone下的实例（注意）</span></span><br><span class="line"><span class="comment">     * CachingServiceInstanceListSupplier启用缓存，不每次访问eureka请求实例列表</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> discoveryClient</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> env</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> zoneConfig</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@Order(Integer.MIN_VALUE)</span></span><br><span class="line">    <span class="keyword">public</span> ServiceInstanceListSupplier <span class="title function_">discoveryClientServiceInstanceListSupplier</span><span class="params">(</span></span><br><span class="line"><span class="params">            DiscoveryClient discoveryClient, Environment env,</span></span><br><span class="line"><span class="params">            LoadBalancerZoneConfig zoneConfig,</span></span><br><span class="line"><span class="params">            ApplicationContext context)</span> &#123;</span><br><span class="line">        isValid = <span class="literal">true</span>;</span><br><span class="line">        <span class="type">ServiceInstanceListSupplier</span> <span class="variable">delegate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SameZoneOnlyServiceInstanceListSupplier</span>(</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">DiscoveryClientServiceInstanceListSupplier</span>(discoveryClient, env),</span><br><span class="line">                zoneConfig</span><br><span class="line">        );</span><br><span class="line">        ObjectProvider&lt;LoadBalancerCacheManager&gt; cacheManagerProvider = context</span><br><span class="line">                .getBeanProvider(LoadBalancerCacheManager.class);</span><br><span class="line">        <span class="keyword">if</span> (cacheManagerProvider.getIfAvailable() != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CachingServiceInstanceListSupplier</span>(</span><br><span class="line">                    delegate,</span><br><span class="line">                    cacheManagerProvider.getIfAvailable()</span><br><span class="line">            );</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> delegate;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ReactorLoadBalancer&lt;ServiceInstance&gt; <span class="title function_">reactorServiceInstanceLoadBalancer</span><span class="params">(</span></span><br><span class="line"><span class="params">            Environment environment,</span></span><br><span class="line"><span class="params">            ServiceInstanceListSupplier serviceInstanceListSupplier,</span></span><br><span class="line"><span class="params">            Tracer tracer)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!isValid) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(<span class="string">&quot;should use the ServiceInstanceListSupplier in this configuration, please check config&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RoundRobinBaseOnTraceIdLoadBalancer</span>(</span><br><span class="line">                name,</span><br><span class="line">                serviceInstanceListSupplier,</span><br><span class="line">                tracer</span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后，<strong>指定默认的负载均衡配置采取这个配置</strong>, 通过注解：</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"><span class="meta">@LoadBalancerClients(defaultConfiguration = &#123;CommonLoadBalancerConfig.class&#125;)</span></span><br></pre></td></tr></table></figure><hr><ul><li>若本号内容有做得不到位的地方（比如：涉及版权或其他问题），请及时联系我们进行整改即可，会在第一时间进行处理。</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;Spring Cloud升级之路-loadbalancer&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>使用Github搭建Hexo技术博客-安装教程</title>
    <link href="http://next.skyheng.com/post/42539.html"/>
    <id>http://next.skyheng.com/post/42539.html</id>
    <published>2020-09-05T07:18:36.000Z</published>
    <updated>2025-11-30T14:41:25.916Z</updated>
    
    <content type="html"><![CDATA[<p>使用Github搭建Hexo技术博客-安装教程</p><span id="more"></span><p><img data-src="http://img.skyheng.com/picture/hexo/hexo_pages.png#align=left&display=inline&height=300&margin=%5Bobject%20Object%5D&originHeight=300&originWidth=529&status=done&style=none&width=529"></p><h2 id="部署前介绍"><a href="#部署前介绍" class="headerlink" title="部署前介绍"></a>部署前介绍</h2><h3 id="Hexo-是什么"><a href="#Hexo-是什么" class="headerlink" title="Hexo 是什么"></a>Hexo 是什么</h3><ul><li>Hexo 的中文官网：<a href="http://hexo.io/zh-cn/">http://hexo.io/zh-cn/</a></li><li>作者 Tommy Chen：<a href="https://zespia.tw/">https://zespia.tw/</a></li><li>在我的理解里面：Hexo 是一个基于 Node.js 快速、简洁且高效的博客框架，可以将 Markdown 文件快速的生成静态网页，托管在<a href="https://pages.github.com/">GitHub Pages</a> 或者<a href="https://pages.coding.net/">Coding Pages </a>上。</li><li>而官网自己是这样说的：</li></ul><blockquote><p>Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown（或其他渲染引擎）解析文章，在几秒内，即可利用靓丽的主题生成静态网页。</p></blockquote><h3 id="为什么要用-Hexo"><a href="#为什么要用-Hexo" class="headerlink" title="为什么要用 Hexo"></a>为什么要用 Hexo</h3><p><img data-src="http://img.skyheng.com/picture/hexo/hexo_idea.png#align=left&display=inline&height=376&margin=%5Bobject%20Object%5D&originHeight=376&originWidth=1440&status=done&style=none&width=1440"></p><ul><li>因为其他博客框架太烂了</li><li>想自己管理博客，不受其他品台的约束</li></ul><h3 id="适合人群"><a href="#适合人群" class="headerlink" title="适合人群"></a>适合人群</h3><ul><li>有开发基础的程序员（或者你是前端开发的前端工程师）</li><li>想搭建一个技术博客的人（真心别搞太多，没那么多精力去搞）</li></ul><h3 id="文章要求"><a href="#文章要求" class="headerlink" title="文章要求"></a>文章要求</h3><ul><li>如果是 Git，Node.js 的新人，则这篇文章不要间断操作，要一气呵成，不然可能会遇到各种问题。</li></ul><h3 id="本文环境"><a href="#本文环境" class="headerlink" title="本文环境"></a>本文环境</h3><blockquote><p>本文在 20171027 修改</p></blockquote><ul><li>系统：Windows 10 专业版（64 位）</li><li>软件：<ul><li>Git：<strong>Git-2.14.1-64-bit</strong></li><li>Notepad++：<strong>6.9.2</strong></li><li>Node.js：<strong>node-v8.7.0-x64</strong></li></ul></li><li>账号和准备：<ul><li>Github：<a href="https://github.com/">https://github.com/</a></li><li>Coding：<a href="https://coding.net/">https://coding.net/</a> 如果同时部署到 coding 上需要</li><li>七牛云：<a href="http://www.qiniu.com/">http://www.qiniu.com/</a> 用来储存图片，当然也有其他方式</li><li>DNSPOD：<a href="https://www.dnspod.cn/">https://www.dnspod.cn/</a></li><li>域名注册：<a href="https://wanwang.aliyun.com/">https://wanwang.aliyun.com/</a> 注册域名绑定博客</li></ul></li></ul><h3 id="搭建所需软件"><a href="#搭建所需软件" class="headerlink" title="搭建所需软件"></a>搭建所需软件</h3><ul><li>各个软件官网：<ul><li>Git：<a href="http://git-scm.com/">http://git-scm.com/</a></li><li>IntelliJ IDEA：<a href="https://www.jetbrains.com/idea/">https://www.jetbrains.com/idea/</a> 在编辑博客中的配置文件和写博客可以用到</li><li>Node.js：<a href="http://nodejs.org/">http://nodejs.org/</a> 镜像站：<a href="https://npm.taobao.org/mirrors/node">https://npm.taobao.org/mirrors/node</a></li><li>Notepad++：<a href="https://notepad-plus-plus.org/">https://notepad-plus-plus.org/</a></li></ul></li><li>所需软件集合：链接：<a href="http://pan.baidu.com/s/1bpyaVRx">http://pan.baidu.com/s/1bpyaVRx</a> 密码：tlhl</li></ul><blockquote><p><strong>Windows 用户</strong></p></blockquote><blockquote><p>由于众所周知的原因，从上面的链接下载 git for windows 最好挂上一个代理，否则下载速度十分缓慢。也可以参考<a href="https://github.com/waylau/git-for-win">这个页面</a>，收录了存储于百度云的下载地址。</p></blockquote><h3 id="文章前提"><a href="#文章前提" class="headerlink" title="文章前提"></a>文章前提</h3><ul><li>如果你对上面要求的软件一个都不了解的话，建议你先看如下内容（只是让你们先了解下，当时别照着文章内容做）：<ul><li><a href="http://www.jianshu.com/p/05289a4bc8b2">如何搭建一个独立博客——简明 Github Pages 与 Hexo 教程</a></li><li><a href="http://www.jianshu.com/p/858ecf233db9">通过 Hexo 在 Github 上搭建博客教程</a></li><li><a href="http://ibruce.info/2013/11/22/hexo-your-blog/">hexo 你的博客</a></li><li><a href="http://www.jianshu.com/p/701b1095da11">手把手教你建 github 技术博客</a></li><li><a href="http://www.jianshu.com/p/05289a4bc8b2">如何搭建一个独立博客——简明 Github Pages 与 Hexo 教程</a></li><li><a href="http://www.jianshu.com/p/e858a90d0a17">windows 下搭建 hexo 博客并将其部署到 GitCafe 终极教程</a></li><li><a href="http://www.jianshu.com/p/db7e64d86067">使用 Hexo 搭建博客（三），博客配置、主题和写作</a></li><li><a href="http://www.jianshu.com/p/e7413116e9d4">Hexo 搭建 WiKi</a></li><li><a href="https://www.zhihu.com/question/28058973">怎么用 hexo 上传一个 README.md 到 github?</a></li></ul></li></ul><h3 id="域名绑定"><a href="#域名绑定" class="headerlink" title="域名绑定"></a>域名绑定</h3><ul><li>如果你一开始就打算要绑定域名，则下面教程中所有可以填写域名的地方你都填写上你要绑定的域名，如果你没独立域名，那就使用 Github 默认给你的：XXXXXX.github.io 域名即可。</li></ul><hr><h2 id="部署开始"><a href="#部署开始" class="headerlink" title="部署开始"></a>部署开始</h2><h3 id="git-安装"><a href="#git-安装" class="headerlink" title="git 安装"></a>git 安装</h3><ul><li>双击运行 <strong>Git-2.14.1-64-bit.exe</strong>，接下来一律下一步，不需要多余的选择，假设你安装的目录位置跟我一样：C:\Program Files\Git</li><li>打开 Git Bash（路径：C:\Program Files\Git\git-bash.exe），输入：<code>git --version</code></li><li>如下图，如果出现：<strong>git version 2.14.1.windows.1</strong>，这表示安装成功<br><img data-src="http://img.skyheng.com/picture/hexo/git.png#alt=%E9%AA%8C%E8%AF%81%20git%20%E5%AE%89%E8%A3%85"></li></ul><h3 id="Node-js-安装"><a href="#Node-js-安装" class="headerlink" title="Node.js 安装"></a>Node.js 安装</h3><ul><li>双击运行 <strong>node-v8.7.0-x64.msi</strong>，接下来一律下一步，不需要多余的选择。</li><li>安装完之后，打开 Git Bash，输入：<code>npm -v</code></li><li>如下图，如果出现：<strong>5.4.2</strong>，则表示 Node.js 安装成功<br><img data-src="http://img.skyheng.com/picture/hexo/node.png#alt=%E9%AA%8C%E8%AF%81%20node.js%20%E5%AE%89%E8%A3%85"></li></ul><h3 id="Node-js-源设置"><a href="#Node-js-源设置" class="headerlink" title="Node.js 源设置"></a>Node.js 源设置</h3><ul><li>在安装 Hexo 之前，先说一下 Node.js 的源，Node.js 官方源默认是：<a href="http://registry.npmjs.org/">http://registry.npmjs.org</a>，但是由于在国外，说不定你使用的时候就抽风无法下载任何软件。所以我们决定暂时使用淘宝提供的源，淘宝源官网：<a href="http://npm.taobao.org/">http://npm.taobao.org/</a></li><li>在 Git Bash 中我们执行下面这一句（这是一整句的）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> cnpm=<span class="string">&quot;npm --registry=https://registry.npm.taobao.org \</span></span><br><span class="line"><span class="string">--cache=<span class="variable">$HOME</span>/.npm/.cache/cnpm \</span></span><br><span class="line"><span class="string">--disturl=https://npm.taobao.org/dist \</span></span><br><span class="line"><span class="string">--userconfig=<span class="variable">$HOME</span>/.cnpmrc&quot;</span></span><br></pre></td></tr></table></figure><h2 id="为-npm-设置代理"><a href="#为-npm-设置代理" class="headerlink" title="为 npm 设置代理"></a>为 npm 设置代理</h2><ul><li>如果电脑使用了代理服务器的(有的公司会使用代码服务器)需要如下设置：</li></ul><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">npm config <span class="built_in">set</span> proxy http://server:port</span><br><span class="line">npm config <span class="built_in">set</span> https-proxy http://server:port</span><br></pre></td></tr></table></figure><p>.npmrc 中的内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">proxy=http://10.74.46.23:8080/</span><br><span class="line">registry=https://registry.npm.taobao.org/</span><br><span class="line">https-proxy=http://10.74.46.23:8080</span><br></pre></td></tr></table></figure><ul><li>如果代理需要认证的话可以这样来设置。</li></ul><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">npm config <span class="built_in">set</span> proxy http://username:password@server:port</span><br><span class="line">npm config <span class="built_in">set</span> https-proxy http://username:pawword@server:port</span><br></pre></td></tr></table></figure><ul><li>如果代理不支持 https 的话需要修改 npm 存放 package 的网站地址。</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">npm config <span class="built_in">set</span> registry <span class="string">&quot;http://registry.npmjs.org/&quot;</span></span><br></pre></td></tr></table></figure><blockquote><p>没有使用代理的忽略这个设置</p></blockquote><ul><li>Mac 下执行：<code>sudo npm install -g cnpm --registry=https://registry.npm.taobao.org</code></li><li>现在验证下是否可以使用淘宝的 cnpm 命令：<code>cnpm info express</code><ul><li>如果能输出一大堆介绍，则说明成功了，以后每次要使用淘宝的源都需要这样来。现在除了默认的 <strong>npm</strong>，还多了一个 <strong>cnpm</strong> 可以使用，我们下面有关安装的讲解内容也都是基于此临时命令。</li><li>如果输出：bash: cnpm: command not found，则表示没成功，需要你在排查下</li></ul></li></ul><h3 id="安装-Hexo-框架"><a href="#安装-Hexo-框架" class="headerlink" title="安装 Hexo 框架"></a>安装 Hexo 框架</h3><ul><li>安装 Hexo（注意，现在是 cnpm 开头了，不是 npm 了）：<code>cnpm install -g hexo-cli</code><ul><li>Mac 下执行：<code>sudo cnpm install -g hexo-cli</code></li><li>安装时间不一定很快，有可能需要等 3 ~ 5 分钟。</li><li>安装完有 WARN 警告也没关系的。</li></ul></li></ul><h3 id="创建-Hexo-项目"><a href="#创建-Hexo-项目" class="headerlink" title="创建 Hexo 项目"></a>创建 Hexo 项目</h3><ul><li>现在假设我要创建一个名为 hexo 的项目，项目目录就放在：E:\blog_space 目录下，所以我们在 E:\blog_space 目录下创建一个 hexo 目录。现在这个项目的全路径是：E:\blog_space\hexo</li><li>打开 Git Bash：</li><li>进入该目录：<code>cd e:/blog_space/hexo</code></li><li>然后执行：<code>hexo init</code>，这个时间也会比较长，也有可能要等几分钟，有显示 WARN 也不用管</li><li>最后执行：<code>cnpm install</code>，有显示 WARN 也不用管</li><li>安装完成之后，E:\blog_space\hexo 目录结构是这样的：<br><img data-src="http://img.skyheng.com/picture/hexo/hexo-menu.png#alt=%E5%AE%89%E8%A3%85%20hexo%20%E5%90%8E%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84"></li><li>现在我们启动 hexo 本地服务，看下默认的博客是怎样的，命令：<code>hexo server</code></li><li>现在用浏览器访问：<a href="http://localhost:4000/">http://localhost:4000/</a>，效果如下图<br><img data-src="http://img.skyheng.com/picture/hexo/hexo-init1.png#alt=%E9%BB%98%E8%AE%A4%E6%A8%A1%E6%9D%BF%E6%95%88%E6%9E%9C"></li><li>如果要停止 hexo 服务：在 Git Bash 下按 <code>Ctrl + C</code> 即可</li></ul><h3 id="选用其他主题"><a href="#选用其他主题" class="headerlink" title="选用其他主题"></a>选用其他主题</h3><ul><li>由于默认主题太大众了，所以现在我们换个主题。</li><li>你可以去这里找主题：<ul><li>hexo-theme：<a href="https://hexo.io/themes/">https://hexo.io/themes/</a></li><li>hexo-github-theme-list：<a href="https://github.com/hexojs/hexo/wiki/Themes">https://github.com/hexojs/hexo/wiki/Themes</a></li><li>有那些好看的 hexo 主题？：<a href="http://www.zhihu.com/question/24422335">http://www.zhihu.com/question/24422335</a></li><li>我这里选择的 <strong>yelee</strong>：GitHub 链接 <a href="https://github.com/MOxFIVE/hexo-theme-yelee">https://github.com/MOxFIVE/hexo-theme-yelee</a></li><li>Yelee 主题使用说明: <a href="http://moxfive.coding.me/yelee/">http://moxfive.coding.me/yelee/</a></li><li>原因是能最大化衬托出：目录、文章内容、代码块。因为我对这个博客的定位就是用来放技术类内容，所以不会让它太杂或是太花。只是目前这个颜色偏浅，后续还需要调整。</li></ul></li><li>现在假设你跟我要用的模板是一样：<ul><li>还是让 Git Bash 保持在 E:\blog_space\hexo 目录下，然后输入命令：<code>git clone https://github.com/MOxFIVE/hexo-theme-yelee.git themes/yelee</code></li><li>这样就在 E:\blog_space\hexo\themes 目录下生成了一个 yelle 文件夹，里面有我们刚刚 clone 下来的主题内容。</li><li>如果以后你不自己修改这个主题的话，可以考虑经常更新下作者的更新内容：<ul><li><code>cd e:/blog_space/hexo/themes/yelee</code></li><li><code>git pull origin master</code></li></ul></li></ul></li><li>下载好主题文件之后，我们现在要修改 E:\blog_space\hexo 目录下的项目配置文件：<strong>_config.yml</strong>，把对应的主题目录名改下，编辑如下图。<br><img data-src="http://img.skyheng.com/picture/hexo/hexo-update.png#alt=%E4%BF%AE%E6%94%B9%E4%B8%BB%E9%A2%98%E7%9B%AE%E5%BD%95"></li><li>更改主题目录名后，我们还要重新生成主题静态内容：</li><li>继续在 Git Bash 中输入命令：</li><li>重新生成静态博客的所有内容：<code>hexo generate</code></li><li>重启 hexo 本地服务：<code>hexo server</code></li><li>重新访问：<a href="http://localhost:4000/">http://localhost:4000/</a>，效果如下图<br><img data-src="http://img.skyheng.com/picture/hexo/hexo-demo.png#alt=%E6%96%B0%E4%B8%BB%E9%A2%98%E6%95%88%E6%9E%9C"></li></ul><h3 id="创建-Github-pages-并-SSH-授权"><a href="#创建-Github-pages-并-SSH-授权" class="headerlink" title="创建 Github pages 并 SSH 授权"></a>创建 Github pages 并 SSH 授权</h3><ul><li>现在假设你已经有一个 Gtihub 账号，你还需要一个特别的仓库，特别在仓库名就是你的 Github 账号登录名，比如我的用户名是：chenjh0611，那我要创建的仓库名字完整滴填写是：<code>chenjh0611.github.io</code></li><li>创建好仓库之后，要本地生成 SSH 秘钥，方便电脑上的 git 软件好提交内容到 Github 上</li><li>在 Git Bash 中，输入：<code>ssh-keygen -t rsa -C &quot;你的邮箱地址&quot;</code>，然后回车，回车，再回车，一共 3 次回车，具体含义自己 Google。</li><li>比如我的：<code>ssh-keygen -t rsa -C &quot;chenjh0611@163.com&quot;</code>：</li><li>此时，生成密钥后，在你电脑目录：C:\Users\你的计算机用户名.ssh 下，会生成两个文件：</li><li>私钥：<strong>id_rsa</strong></li><li>公钥：<strong>id_rsa.pub</strong></li><li>如果生成的不是这样的文件，那删除掉这两个生成的，重新执行上面的命令，让它再一次生成。</li><li>现在用记事本打开 id_rsa.pub，复制文件中的所有内容。</li><li>访问：<a href="https://github.com/settings/ssh">https://github.com/settings/ssh</a>，添加新秘钥，效果如下图<br><img data-src="http://img.skyheng.com/picture/hexo/hexo-start.png#alt=%E6%B7%BB%E5%8A%A0%E5%AF%86%E9%92%A5"></li><li>Title：自己随便取</li><li>Key：把刚刚复制的都粘贴进来</li></ul><h3 id="把本地的博客内容同步到-Github-上"><a href="#把本地的博客内容同步到-Github-上" class="headerlink" title="把本地的博客内容同步到 Github 上"></a>把本地的博客内容同步到 Github 上</h3><ul><li>要把本地的静态博客同步到 Github，我们还需要先安装两个跟部署相关的 hexo 插件：<ul><li>继续在 Git Bash 中输入：</li><li><code>cnpm install hexo -server --save</code></li><li><code>cnpm install hexo-deployer-git --save</code></li></ul></li><li>编辑全局 hexo 的配置文件：<strong>_config.yml</strong><ul><li>官网对此配置的介绍：<a href="https://hexo.io/zh-cn/docs/configuration.html">https://hexo.io/zh-cn/docs/configuration.html</a></li><li>我自己的编辑内容初稿（你需要认真看的是含有中文注释的内容）：</li></ul></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Hexo Configuration</span></span><br><span class="line"><span class="comment">## Docs: https://hexo.io/docs/configuration.html</span></span><br><span class="line"><span class="comment">## Source: https://github.com/hexojs/hexo/</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Site 这一块区域主要是设置博客的主要说明，需要注意的是：每个冒号后面都是有一个空格，然后再书写自己的内容的s</span></span><br><span class="line">title: Chenjh Code  <span class="comment">#网站标题</span></span><br><span class="line">subtitle: 这里只有代码相关,要了解更多 &gt;&gt; www.skyheng.com <span class="comment">#网站副标题</span></span><br><span class="line">description: 这里是 www.skyheng.com 一部分</span><br><span class="line">author: Chenjh</span><br><span class="line">email: 1225948009@qq.com</span><br><span class="line">language: zh-CN</span><br><span class="line">timezone:   <span class="comment">#网站时区。Hexo 默认使用您电脑的时区</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># URL 这一块一般可以设置的是 url 这个参数，比如我要设置绑定域名的，这里就需要填写我的域名信息</span></span><br><span class="line"><span class="comment">## If your site is put in a subdirectory, set url as &#x27;http://yoursite.com/child&#x27; and root as &#x27;/child/&#x27;</span></span><br><span class="line">url: http://code.skyheng.com</span><br><span class="line">root: /</span><br><span class="line">permalink: :year/:month/:day/:title/</span><br><span class="line">permalink_defaults:</span><br><span class="line"></span><br><span class="line"><span class="comment"># Directory</span></span><br><span class="line">source_dir: <span class="built_in">source</span> <span class="comment">#源文件夹，这个文件夹用来存放内容。</span></span><br><span class="line">public_dir: public <span class="comment">#公共文件夹，这个文件夹用于存放生成的站点文件</span></span><br><span class="line">tag_dir: tags <span class="comment">#标签文件夹</span></span><br><span class="line">archive_dir: archives <span class="comment">#归档文件夹</span></span><br><span class="line">category_dir: categories <span class="comment">#分类文件夹</span></span><br><span class="line">code_dir: downloads/code <span class="comment">#nclude code 文件夹</span></span><br><span class="line">i18n_dir: :lang <span class="comment">#国际化（i18n）文件夹</span></span><br><span class="line">skip_render:  <span class="comment">#跳过指定文件的渲染，您可使用 glob 表达式来匹配路径</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Writing</span></span><br><span class="line">new_post_name: :year-:month-:day.:title.md <span class="comment">#新建文章默认文件名</span></span><br><span class="line">default_layout: post <span class="comment"># 默认布局</span></span><br><span class="line">titlecase: <span class="literal">false</span> <span class="comment"># Transform title into titlecase</span></span><br><span class="line">external_link: <span class="literal">true</span> <span class="comment"># 在新标签中打开一个外部链接，默认为true</span></span><br><span class="line">filename_case: 0</span><br><span class="line">render_drafts: <span class="literal">false</span> <span class="comment">#是否渲染_drafts目录下的文章，默认为false</span></span><br><span class="line">post_asset_folder: <span class="literal">true</span> <span class="comment">#启动 Asset 文件夹</span></span><br><span class="line">relative_link: <span class="literal">false</span> <span class="comment">#把链接改为与根目录的相对位址，默认false</span></span><br><span class="line">future: <span class="literal">true</span> <span class="comment">#显示未来的文章，默认false</span></span><br><span class="line">highlight:  <span class="comment">#代码块的设置</span></span><br><span class="line">  <span class="built_in">enable</span>: <span class="literal">true</span></span><br><span class="line">  line_number: <span class="literal">true</span></span><br><span class="line">  auto_detect: <span class="literal">false</span></span><br><span class="line">  tab_replace:</span><br><span class="line"></span><br><span class="line"><span class="comment"># Category &amp; Tag #分类和标签的设置</span></span><br><span class="line">default_category: uncategorized <span class="comment">#默认分类</span></span><br><span class="line">category_map:</span><br><span class="line">tag_map:</span><br><span class="line"></span><br><span class="line"><span class="comment"># Date / Time format</span></span><br><span class="line"><span class="comment">## Hexo uses Moment.js to parse and display date</span></span><br><span class="line"><span class="comment">## You can customize the date format as defined in</span></span><br><span class="line"><span class="comment">## http://momentjs.com/docs/#/displaying/format/</span></span><br><span class="line">date_format: YYYY-MM-DD</span><br><span class="line">time_format: HH:mm:ss</span><br><span class="line"></span><br><span class="line"><span class="comment"># Pagination</span></span><br><span class="line"><span class="comment">## Set per_page to 0 to disable pagination</span></span><br><span class="line">per_page: 10</span><br><span class="line">pagination_dir: page</span><br><span class="line"></span><br><span class="line"><span class="comment"># Extensions</span></span><br><span class="line"><span class="comment">## Plugins: https://hexo.io/plugins/</span></span><br><span class="line"><span class="comment">## Themes: https://hexo.io/themes/</span></span><br><span class="line">theme: next <span class="comment"># next  yelee</span></span><br><span class="line"></span><br><span class="line">search:</span><br><span class="line">  path: search.xml</span><br><span class="line">  field: all</span><br><span class="line"></span><br><span class="line"><span class="comment"># Deployment</span></span><br><span class="line"><span class="comment">## 这里是重点，这里是修改发布地址，因为我们前面已经加了 SSH 密钥信息在 Github 设置里面了，所以只要我们电脑里面持有那两个密钥文件就可以无需密码地跟 Github 做同步。</span></span><br><span class="line"><span class="comment">## 需要注意的是这里的 repo 采用的是 ssh 的地址，而不是 https 的。分支我们默认采用 master 分支，以后你翅膀硬了要换其他也无所谓。</span></span><br><span class="line"><span class="comment">## Docs: https://hexo.io/docs/deployment.html</span></span><br><span class="line">deploy:</span><br><span class="line">  <span class="built_in">type</span>: git</span><br><span class="line">  repo:</span><br><span class="line">      github: git@github.com:chenjh0611/chenjh0611.github.io.git,master</span><br><span class="line">      coding: git@git.coding.net:chenjh0719/chenjh0719.git,master</span><br></pre></td></tr></table></figure><ul><li>编辑全局配置后我们需要重新部署：</li><li>继续在 Git Bash 中输入命令：</li><li>先清除掉已经生成的旧文件：<code>hexo clean</code></li><li>再生成一次静态文件：<code>hexo generate</code></li><li>在本地预览下：<code>hexo server</code></li><li>本地没问题之后，Ctrl + C 停掉本地预览，使用部署命令部署到 Github 上：<code>hexo deploy</code>，有弹出下面提示框，请输入：<code>yes</code><br><img data-src="http://img.skyheng.com/picture/hexo/ssh-alert.png#alt=%E7%A1%AE%E8%AE%A4%E6%8F%90%E4%BA%A4"></li><li>提交成功效果如下：<br><img data-src="http://img.skyheng.com/picture/hexo/deploy.png#alt=%E6%8F%90%E4%BA%A4%E6%88%90%E5%8A%9F"></li><li>访问服务器地址进行检查：<a href="http://chenjh0611.github.io/">http://chenjh0611.github.io</a></li><li>通过上面几次流程我们也就可以总结：以后，每次发表新文章要部署都按这样的流程来：<ul><li><code>hexo clean</code></li><li><code>hexo generate</code></li><li><code>hexo deploy</code></li></ul></li><li>也因为这几个命令太频繁了，所以又有了精简版的命令：<ul><li><code>hexo clean == hexo clean</code></li><li><code>hexo g == hexo generate</code></li><li><code>hexo s == hexo server</code></li><li><code>hexo d == hexo deploy</code></li></ul></li></ul><h3 id="绑定域名"><a href="#绑定域名" class="headerlink" title="绑定域名"></a>绑定域名</h3><ul><li>绑定域名不排除会遇到很多网络问题或是七七八八，所以这里先提供先官网的一些说明：<ul><li><a href="https://help.github.com/articles/setting-up-your-pages-site-repository/">https://help.github.com/articles/setting-up-your-pages-site-repository/</a></li><li><a href="https://help.github.com/articles/quick-start-setting-up-a-custom-domain/">https://help.github.com/articles/quick-start-setting-up-a-custom-domain/</a></li><li><a href="https://help.github.com/articles/setting-up-an-apex-domain/">https://help.github.com/articles/setting-up-an-apex-domain/</a></li><li><a href="https://help.github.com/articles/troubleshooting-custom-domains/">https://help.github.com/articles/troubleshooting-custom-domains/</a></li><li><a href="https://help.github.com/articles/custom-domain-redirects-for-github-pages-sites/">https://help.github.com/articles/custom-domain-redirects-for-github-pages-sites/</a></li></ul></li><li>首先我们要一个 CNAME 文件（文件名叫 CNAME，没有文件后缀的），把该文件放在 E:\blog_space\hexo\source 目录下，以后一些需要放在根目录的资源文件都可以放这里。如果你找不到这样的文件可以到我的项目上下载：<a href="https://github.com/chenjh0611/chenjh0611.github.io">https://github.com/chenjh0611/chenjh0611.github.io</a></li><li>CNAME 上的内容需要写你具体要绑定的域名信息，比如我是：<strong>code.skyheng.com</strong>：</li><li>接着我们需要到阿里云后台上设置域名解析：<a href="https://www.aliyun.com/">https://www.aliyun.com/</a><br><img data-src="http://img.skyheng.com/picture/hexo/dc-demo.png#alt=%E8%AE%BE%E7%BD%AE%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90"></li><li>设置好之后，等过几分钟域名解析好之后，我们访问：<a href="http://code.skyheng.com/">http://code.skyheng.com</a>，效果如下：<br><img data-src="http://img.skyheng.com/picture/hexo/blog-demo.png#alt=%E5%9F%9F%E5%90%8D%E8%AE%BF%E9%97%AE%E6%95%88%E6%9E%9C"></li></ul><h3 id="整合-Notepad-提高效率"><a href="#整合-Notepad-提高效率" class="headerlink" title="整合 Notepad++ 提高效率"></a>整合 Notepad++ 提高效率</h3><ul><li>为了提交写作效率，我个人建议使用 Notepad++ 作为 Markdown 编辑工具</li><li>现在我们用 Notepad++ 打开我们本地目录：E:\blog_space\hexo，打开后效果如下图：<br><img data-src="http://img.skyheng.com/picture/hexo/notepad-edit.png#alt=Notepad%2B%2B"></li><li>hexo 新文章内容的开头需要这样定义：<ul><li>categories：表示文章所属分类</li><li>tags：表示文章所属标签</li></ul></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: 这是文章标题</span><br><span class="line">categories:</span><br><span class="line">  - hexo</span><br><span class="line">tags:</span><br><span class="line">  - hexo</span><br><span class="line">  - git</span><br><span class="line">  - github</span><br><span class="line">  - nodejs</span><br><span class="line"><span class="built_in">date</span>: 2015-05-01 10:46:18</span><br><span class="line">description: 这里可以写描述</span><br><span class="line">---</span><br></pre></td></tr></table></figure><h2 id="结束语"><a href="#结束语" class="headerlink" title="结束语"></a>结束语</h2><ul><li>我希望从这一篇你也可以为自己搭建一个属于你自己的博客，在博客中畅写。</li><li>最后，祝你搭建博客成功，创造属于你的世界！</li></ul><h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><ul><li><a href="http://blog.csdn.net/masterant_d/article/details/54598391">基于 Hexo+Node.js+github+coding 搭建个人博客——基础篇(从菜鸟到放弃)</a></li><li><a href="http://blog.csdn.net/masterant_d/article/details/56839222">基于 Hexo+Node.js+github+coding 搭建个人博客——进阶篇(从入门到入土)</a></li><li>Next 主题的文章：<ul><li>Hexo(Pages)—博客搭建同步 GitHub&amp;Coding：<a href="https://www.tuicool.com/articles/NfAj2er">https://www.tuicool.com/articles/NfAj2er</a></li><li>Hexo(Pages)—优化博客「续更」：<a href="https://www.tuicool.com/articles/aUbMfyz">https://www.tuicool.com/articles/aUbMfyz</a></li><li>基于 Hexo + GitHub Pages 搭建个人博客（一）：<a href="http://www.cnblogs.com/compassblog/p/8627873.html">http://www.cnblogs.com/compassblog/p/8627873.html</a></li><li>基于 Hexo + GitHub Pages 搭建个人博客（二）：<a href="http://www.cnblogs.com/compassblog/p/8629626.html">http://www.cnblogs.com/compassblog/p/8629626.html</a></li><li>基于 Hexo + GitHub Pages 搭建个人博客（三）：<a href="http://www.cnblogs.com/compassblog/p/8911112.html">http://www.cnblogs.com/compassblog/p/8911112.html</a></li></ul></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;使用Github搭建Hexo技术博客-安装教程&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Vue开发技巧</title>
    <link href="http://next.skyheng.com/post/32624.html"/>
    <id>http://next.skyheng.com/post/32624.html</id>
    <published>2020-09-04T17:03:42.000Z</published>
    <updated>2025-11-30T14:41:25.916Z</updated>
    
    <content type="html"><![CDATA[<p>Vue开发技巧</p><span id="more"></span><h1 id="1-require-context"><a href="#1-require-context" class="headerlink" title="1.require.context()"></a>1.require.context()</h1><p>1.场景:如页面需要导入多个组件,原始写法:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> titleCom <span class="keyword">from</span> <span class="string">&quot;@/components/home/titleCom&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> bannerCom <span class="keyword">from</span> <span class="string">&quot;@/components/home/bannerCom&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> cellCom <span class="keyword">from</span> <span class="string">&quot;@/components/home/cellCom&quot;</span>;</span><br><span class="line"><span class="attr">components</span>: &#123;</span><br><span class="line">  titleCom, bannerCom, cellCom;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>2.这样就写了大量重复的代码,利用 require.context 可以写成</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;path&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> files = <span class="built_in">require</span>.<span class="title function_">context</span>(<span class="string">&quot;@/components/home&quot;</span>, <span class="literal">false</span>, <span class="regexp">/\.vue$/</span>);</span><br><span class="line"><span class="keyword">const</span> modules = &#123;&#125;;</span><br><span class="line">files.<span class="title function_">keys</span>().<span class="title function_">forEach</span>(<span class="function">(<span class="params">key</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> name = path.<span class="title function_">basename</span>(key, <span class="string">&quot;.vue&quot;</span>);</span><br><span class="line">  modules[name] = <span class="title function_">files</span>(key).<span class="property">default</span> || <span class="title function_">files</span>(key);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="attr">components</span>: modules;</span><br></pre></td></tr></table></figure><p>这样不管页面引入多少组件,都可以使用这个方法<br>3.API 方法</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">实际上是 webpack 的方法,vue 工程一般基于 webpack,所以可以使用</span><br><span class="line">require.context(directory,useSubdirectories,regExp)</span><br><span class="line">接收三个参数:</span><br><span class="line">directory：说明需要检索的目录</span><br><span class="line">useSubdirectories：是否检索子目录</span><br><span class="line">regExp: 匹配文件的正则表达式,一般是文件名</span><br></pre></td></tr></table></figure><h1 id="2-watch"><a href="#2-watch" class="headerlink" title="2.watch"></a>2.watch</h1><h2 id="2-1-常用用法"><a href="#2-1-常用用法" class="headerlink" title="2.1 常用用法"></a>2.1 常用用法</h2><p>1.场景:表格初始进来需要调查询接口 getList(),然后 input 改变会重新查询</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">created</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="title function_">getList</span>()</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">watch</span>: &#123;</span><br><span class="line">  <span class="title function_">inpVal</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">getList</span>()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-2-立即执行"><a href="#2-2-立即执行" class="headerlink" title="2.2 立即执行"></a>2.2 立即执行</h2><p>2.可以直接利用 watch 的 immediate 和 handler 属性简写</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">watch</span>: &#123;</span><br><span class="line">  <span class="attr">inpVal</span>:&#123;</span><br><span class="line">    <span class="attr">handler</span>: <span class="string">&#x27;getList&#x27;</span>,</span><br><span class="line">      <span class="attr">immediate</span>: <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-3-深度监听"><a href="#2-3-深度监听" class="headerlink" title="2.3 深度监听"></a>2.3 深度监听</h2><p>3.watch 的 deep 属性,深度监听,也就是监听复杂数据类型</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">watch</span>:&#123;</span><br><span class="line">  <span class="attr">inpValObj</span>:&#123;</span><br><span class="line">    <span class="title function_">handler</span>(<span class="params">newVal,oldVal</span>)&#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(newVal)</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(oldVal)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">deep</span>:<span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>此时发现 oldVal 和 newVal 值一样; 因为它们索引同一个对象&#x2F;数组,Vue 不会保留修改之前值的副本; 所以深度监听虽然可以监听到对象的变化,但是无法监听到具体对象里面那个属性的变化</p><h1 id="3-14-种组件通讯"><a href="#3-14-种组件通讯" class="headerlink" title="3. 14 种组件通讯"></a>3. 14 种组件通讯</h1><h2 id="3-1-props"><a href="#3-1-props" class="headerlink" title="3.1 props"></a>3.1 props</h2><p>这个应该非常属性,就是父传子的属性; props 值可以是一个数组或对象;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 数组:不建议使用</span></span><br><span class="line"><span class="attr">props</span>:[]</span><br><span class="line"><span class="comment">// 对象</span></span><br><span class="line"><span class="attr">props</span>:&#123;</span><br><span class="line"> <span class="attr">inpVal</span>:&#123;</span><br><span class="line">  <span class="attr">type</span>:<span class="title class_">Number</span>, <span class="comment">//传入值限定类型</span></span><br><span class="line">  <span class="comment">// type 值可为String,Number,Boolean,Array,Object,Date,Function,Symbol</span></span><br><span class="line">  <span class="comment">// type 还可以是一个自定义的构造函数，并且通过 instanceof 来进行检查确认</span></span><br><span class="line">  <span class="attr">required</span>: <span class="literal">true</span>, <span class="comment">//是否必传</span></span><br><span class="line">  <span class="attr">default</span>:<span class="number">200</span>,  <span class="comment">//默认值,对象或数组默认值必须从一个工厂函数获取如 default:()=&gt;[]</span></span><br><span class="line">  <span class="attr">validator</span>:<span class="function">(<span class="params">value</span>)=&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 这个值必须匹配下列字符串中的一个</span></span><br><span class="line">    <span class="keyword">return</span> [<span class="string">&#x27;success&#x27;</span>, <span class="string">&#x27;warning&#x27;</span>, <span class="string">&#x27;danger&#x27;</span>].<span class="title function_">indexOf</span>(value) !== -<span class="number">1</span></span><br><span class="line">  &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-2-emit"><a href="#3-2-emit" class="headerlink" title="3.2 $emit"></a>3.2 $emit</h2><p>这个也应该非常常见,触发子组件触发父组件给自己绑定的事件,其实就是子传父的方法</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;home @title=&quot;title&quot;&gt;</span><br><span class="line">// 子组件</span><br><span class="line">this.$emit(&#x27;title&#x27;,[&#123;title:&#x27;这是title&#x27;&#125;])</span><br></pre></td></tr></table></figure><h2 id="3-3-vuex"><a href="#3-3-vuex" class="headerlink" title="3.3 vuex"></a>3.3 vuex</h2><p>1.这个也是很常用的,vuex 是一个状态管理器 2.是一个独立的插件,适合数据共享多的项目里面,因为如果只是简单的通讯,使用起来会比较重 3.API</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">state:定义存贮数据的仓库 ,可通过this.$store.state 或mapState访问</span><br><span class="line">getter:获取 store 值,可认为是 store 的计算属性,可通过this.$store.getter 或 mapGetters访问</span><br><span class="line">mutation:同步改变 store 值,为什么会设计成同步,因为mutation是直接改变 store 值, vue 对操作进行了记录,如果是异步无法追踪改变.可通过mapMutations调用</span><br><span class="line">action:异步调用函数执行mutation,进而改变 store 值,可通过 this.$dispatch或mapActions</span><br><span class="line">modules:模块,如果状态过多,可以拆分成模块,最后在入口通过...解构引入</span><br></pre></td></tr></table></figure><h2 id="3-4-listeners"><a href="#3-4-listeners" class="headerlink" title="3.4 listeners"></a>3.4 <img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868209763-80b06e11-ba9f-4c37-a4e0-6c743add5cd3.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=65&size=0&status=done&style=none&width=65">listeners</h2><p>2.4.0 新增 这两个是不常用属性,但是高级用法很常见; 1.<img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868209797-260691e4-8075-493c-b65c-bb6227a9769a.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=622&size=0&status=done&style=none&width=622">attrs 获取子传父中未在 props 定义的值</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;home title=&quot;这是标题&quot; width=&quot;80&quot; height=&quot;80&quot; imgUrl=&quot;imgUrl&quot; /&gt;</span><br><span class="line">// 子组件 mounted() &#123; console.log(this.$attrs) //&#123;title: &quot;这是标题&quot;, width:</span><br><span class="line">&quot;80&quot;, height: &quot;80&quot;, imgUrl: &quot;imgUrl&quot;&#125; &#125;</span><br></pre></td></tr></table></figure><p>相对应的如果子组件定义了 props,打印的值就是剔除定义的属性</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">props</span>: &#123;</span><br><span class="line">  <span class="attr">width</span>: &#123;</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">String</span>,</span><br><span class="line">    <span class="attr">default</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">$attrs</span>) <span class="comment">//&#123;title: &quot;这是标题&quot;, height: &quot;80&quot;, imgUrl: &quot;imgUrl&quot;&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>2.<img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868209814-ac895a1a-921e-4850-904d-b1503fa76606.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=734&size=0&status=done&style=none&width=734">listeners” 传入内部组件——在创建更高层次的组件时非常有用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;home @change=&quot;change&quot; /&gt;</span><br><span class="line">// 子组件 mounted() &#123; console.log(this.$listeners) //即可拿到 change 事件 &#125;</span><br></pre></td></tr></table></figure><p>如果是孙组件要访问父组件的属性和调用方法,直接一级一级传下去就可以<br>3.inheritAttrs</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;home title=&quot;这是标题&quot; width=&quot;80&quot; height=&quot;80&quot; imgUrl=&quot;imgUrl&quot; /&gt;</span><br><span class="line">// 子组件 mounted() &#123; console.log(this.$attrs) //&#123;title: &quot;这是标题&quot;, width:</span><br><span class="line">&quot;80&quot;, height: &quot;80&quot;, imgUrl: &quot;imgUrl&quot;&#125; &#125;,</span><br><span class="line">inheritAttrs默认值为true，true的意思是将父组件中除了props外的属性添加到子组件的根节点上(说明，即使设置为true，子组件仍然可以通过$attr获取到props意外的属性)</span><br><span class="line">将inheritAttrs:false后,属性就不会显示在根节点上了</span><br></pre></td></tr></table></figure><h2 id="3-5-provide-和-inject"><a href="#3-5-provide-和-inject" class="headerlink" title="3.5 provide 和 inject"></a>3.5 provide 和 inject</h2><p>2.2.0 新增 描述: provide 和 inject 主要为高阶插件&#x2F;组件库提供用例。并不推荐直接用于应用程序代码中; 并且这对选项需要一起使用; 以允许一个祖先组件向其所有子孙后代注入一个依赖，不论组件层次有多深，并在起上下游关系成立的时间里始终生效。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//父组件:</span></span><br><span class="line"><span class="attr">provide</span>: &#123; <span class="comment">//provide 是一个对象,提供一个属性或方法</span></span><br><span class="line">  <span class="attr">foo</span>: <span class="string">&#x27;这是 foo&#x27;</span>,</span><br><span class="line">  <span class="attr">fooMethod</span>:<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;父组件 fooMethod 被调用&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="comment">// 子或者孙子组件</span></span><br><span class="line"><span class="attr">inject</span>: [<span class="string">&#x27;foo&#x27;</span>,<span class="string">&#x27;fooMethod&#x27;</span>], <span class="comment">//数组或者对象,注入到子组件</span></span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="title function_">fooMethod</span>()</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">foo</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//在父组件下面所有的子组件都可以利用inject</span></span><br></pre></td></tr></table></figure><p>provide 和 inject 绑定并不是可响应的。这是官方刻意为之的。 然而，如果你传入了一个可监听的对象，那么其对象的属性还是可响应的,对象是因为是引用类型</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//父组件:</span></span><br><span class="line"><span class="attr">provide</span>: &#123;</span><br><span class="line">  <span class="attr">foo</span>: <span class="string">&#x27;这是 foo&#x27;</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">foo</span>=<span class="string">&#x27;这是新的 foo&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 子或者孙子组件</span></span><br><span class="line"><span class="attr">inject</span>: [<span class="string">&#x27;foo&#x27;</span>],</span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">foo</span>) <span class="comment">//子组件打印的还是&#x27;这是 foo&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-6-children"><a href="#3-6-children" class="headerlink" title="3.6 children"></a>3.6 <img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868210236-7ca67428-274e-436a-b317-6aa2a488b6c9.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=81&size=0&status=done&style=none&width=81">children</h2><p><img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868210156-d97ddf86-9314-4d43-92d1-2b84738e0204.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=138&size=0&status=done&style=none&width=138">children:子实例</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//父组件</span></span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">$children</span>)</span><br><span class="line">  <span class="comment">//可以拿到 一级子组件的属性和方法</span></span><br><span class="line">  <span class="comment">//所以就可以直接改变 data,或者调用 methods 方法</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//子组件</span></span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">$parent</span>) <span class="comment">//可以拿到 parent 的属性和方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868210189-af799fdc-615f-4527-9518-0cc3d3bfb9f5.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=97&size=0&status=done&style=none&width=97">parent 并不保证顺序，也不是响应式的 只能拿到一级父组件和子组件</p><h2 id="3-7-refs"><a href="#3-7-refs" class="headerlink" title="3.7 $refs"></a>3.7 $refs</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;home ref=&quot;home&quot; /&gt;</span><br><span class="line">mounted()&#123; console.log(this.$refs.home) //即可拿到子组件的实例,就可以直接操作</span><br><span class="line">data 和 methods &#125;</span><br></pre></td></tr></table></figure><h2 id="3-8-root"><a href="#3-8-root" class="headerlink" title="3.8 $root"></a>3.8 $root</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 父组件</span></span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">$root</span>) <span class="comment">//获取根实例,最后所有组件都是挂载到根实例上</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">$root</span>.<span class="property">$children</span>[<span class="number">0</span>]) <span class="comment">//获取根实例的一级子组件</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">$root</span>.<span class="property">$children</span>[<span class="number">0</span>].<span class="property">$children</span>[<span class="number">0</span>]) <span class="comment">//获取根实例的二级子组件</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-9-sync"><a href="#3-9-sync" class="headerlink" title="3.9 .sync"></a>3.9 .sync</h2><p>在 <a href="mailto:&#x76;&#x75;&#x65;&#x40;&#49;&#46;&#120;">vue@1.x</a> 的时候曾作为双向绑定功能存在，即子组件可以修改父组件中的值; 在 <a href="mailto:&#118;&#117;&#101;&#x40;&#50;&#46;&#x30;">vue@2.0</a> 的由于违背单项数据流的设计被干掉了; 在 <a href="mailto:&#x76;&#x75;&#x65;&#64;&#50;&#46;&#x33;&#x2e;&#x30;">vue@2.3.0</a>+ 以上版本又重新引入了这个 .sync 修饰符;</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;home :title.sync=&quot;title&quot; /&gt;</span><br><span class="line">//编译时会被扩展为</span><br><span class="line">&lt;home :title=&quot;title&quot; @update:title=&quot;(val) =&gt; (title = val)&quot; /&gt;</span><br><span class="line">// 子组件 // 所以子组件可以通过$emit 触发 update 方法改变 mounted()&#123;</span><br><span class="line">this.$emit(&quot;update:title&quot;, &#x27;这是新的title&#x27;) &#125;</span><br></pre></td></tr></table></figure><h2 id="3-10-v-slot"><a href="#3-10-v-slot" class="headerlink" title="3.10 v-slot"></a>3.10 v-slot</h2><p>2.6.0 新增 1.slot,slot-cope,scope 在 2.6.0 中都被废弃,但未被移除 2.作用就是将父组件的 template 传入子组件 3.插槽分类: A.匿名插槽(也叫默认插槽): 没有命名,有且只有一个;</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;todo-list&gt; </span><br><span class="line">    &lt;template v-slot:default&gt;</span><br><span class="line">       任意内容</span><br><span class="line">       &lt;p&gt;我是匿名插槽 &lt;/p&gt;</span><br><span class="line">    &lt;/template&gt;</span><br><span class="line">&lt;/todo-list&gt;</span><br><span class="line">// 子组件</span><br><span class="line">&lt;slot&gt;我是默认值&lt;/slot&gt;</span><br><span class="line">//v-slot:default写上感觉和具名写法比较统一,容易理解,也可以不用写</span><br></pre></td></tr></table></figure><p>B.具名插槽: 相对匿名插槽组件 slot 标签带 name 命名的;</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;todo-list&gt; </span><br><span class="line">    &lt;template v-slot:todo&gt;</span><br><span class="line">       任意内容</span><br><span class="line">       &lt;p&gt;我是匿名插槽 &lt;/p&gt;</span><br><span class="line">    &lt;/template&gt;</span><br><span class="line">&lt;/todo-list&gt;</span><br><span class="line">//子组件</span><br><span class="line">&lt;slot name=&quot;todo&quot;&gt;我是默认值&lt;/slot&gt;</span><br></pre></td></tr></table></figure><p>C.作用域插槽: 子组件内数据可以被父页面拿到(解决了数据只能从父页面传递给子组件)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">// 父组件</span><br><span class="line">&lt;todo-list&gt;</span><br><span class="line"> &lt;template v-slot:todo=&quot;slotProps&quot; &gt;</span><br><span class="line">   &#123;&#123;slotProps.user.firstName&#125;&#125;</span><br><span class="line"> &lt;/template&gt; </span><br><span class="line">&lt;/todo-list&gt;</span><br><span class="line">//slotProps 可以随意命名 //slotProps</span><br><span class="line">接取的是子组件标签slot上属性数据的集合所有v-bind:user=&quot;user&quot; // 子组件</span><br><span class="line">&lt;slot name=&quot;todo&quot; :user=&quot;user&quot; :test=&quot;test&quot;&gt;</span><br><span class="line">    &#123;&#123; user.lastName &#125;&#125;</span><br><span class="line"> &lt;/slot&gt;</span><br><span class="line">data() &#123; return &#123; user:&#123; lastName:&quot;Zhang&quot;, firstName:&quot;yue&quot; &#125;, test:[1,2,3,4] &#125;</span><br><span class="line">&#125;, // &#123;&#123; user.lastName &#125;&#125;是默认数据 v-slot:todo 当父页面没有(=&quot;slotProps&quot;)</span><br></pre></td></tr></table></figure><h2 id="3-11-EventBus"><a href="#3-11-EventBus" class="headerlink" title="3.11 EventBus"></a>3.11 EventBus</h2><p>1.就是声明一个全局 Vue 实例变量 EventBus , 把所有的通信数据，事件监听都存储到这个变量上; 2.类似于 Vuex。但这种方式只适用于极小的项目 3.原理就是利用<img data-src="https://cdn.nlark.com/yuque/0/2020/svg/416908/1589868210193-4e698dd0-913f-4fa6-961c-d24a97f2ac46.svg#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=30&originWidth=42&size=0&status=done&style=none&width=42">emit 并实例化一个全局 vue 实现数据共享</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在 main.js</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">$eventBus</span> = <span class="keyword">new</span> <span class="title class_">Vue</span>();</span><br><span class="line"><span class="comment">// 传值组件</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$eventBus</span>.$emit(<span class="string">&quot;eventTarget&quot;</span>, <span class="string">&quot;这是eventTarget传过来的值&quot;</span>);</span><br><span class="line"><span class="comment">// 接收组件</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$eventBus</span>.$on(<span class="string">&quot;eventTarget&quot;</span>, <span class="function">(<span class="params">v</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;eventTarget&quot;</span>, v); <span class="comment">//这是eventTarget传过来的值</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>4.可以实现平级,嵌套组件传值,但是对应的事件名 eventTarget 必须是全局唯一的</p><h2 id="3-12-broadcast-和-dispatch"><a href="#3-12-broadcast-和-dispatch" class="headerlink" title="3.12 broadcast 和 dispatch"></a>3.12 broadcast 和 dispatch</h2><p>vue 1.x 有这两个方法,事件广播和派发,但是 vue 2.x 删除了 下面是对两个方法进行的封装</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">broadcast</span>(<span class="params">componentName, eventName, params</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">$children</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">child</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> name = child.<span class="property">$options</span>.<span class="property">componentName</span>;</span><br><span class="line">    <span class="keyword">if</span> (name === componentName) &#123;</span><br><span class="line">      child.<span class="property">$emit</span>.<span class="title function_">apply</span>(child, [eventName].<span class="title function_">concat</span>(params));</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      broadcast.<span class="title function_">apply</span>(child, [componentName, eventName].<span class="title function_">concat</span>(params));</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="title function_">dispatch</span>(<span class="params">componentName, eventName, params</span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> parent = <span class="variable language_">this</span>.<span class="property">$parent</span>;</span><br><span class="line">      <span class="keyword">var</span> name = parent.<span class="property">$options</span>.<span class="property">componentName</span>;</span><br><span class="line">      <span class="keyword">while</span> (parent &amp;&amp; (!name || name !== componentName)) &#123;</span><br><span class="line">        parent = parent.<span class="property">$parent</span>;</span><br><span class="line">        <span class="keyword">if</span> (parent) &#123;</span><br><span class="line">          name = parent.<span class="property">$options</span>.<span class="property">componentName</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (parent) &#123;</span><br><span class="line">        parent.<span class="property">$emit</span>.<span class="title function_">apply</span>(parent, [eventName].<span class="title function_">concat</span>(params));</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">broadcast</span>(<span class="params">componentName, eventName, params</span>) &#123;</span><br><span class="line">      broadcast.<span class="title function_">call</span>(<span class="variable language_">this</span>, componentName, eventName, params);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="3-13-路由传参"><a href="#3-13-路由传参" class="headerlink" title="3.13 路由传参"></a>3.13 路由传参</h2><p>1.方案一</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 路由定义</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/describe/:id&#x27;</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;Describe&#x27;</span>,</span><br><span class="line">  <span class="attr">component</span>: <span class="title class_">Describe</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 页面传参</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$router</span>.<span class="title function_">push</span>(&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">`/describe/<span class="subst">$&#123;id&#125;</span>`</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 页面获取</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$route</span>.<span class="property">params</span>.<span class="property">id</span></span><br></pre></td></tr></table></figure><p>2.方案二</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 路由定义</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/describe&#x27;</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;Describe&#x27;</span>,</span><br><span class="line">  <span class="attr">component</span>: <span class="title class_">Describe</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 页面传参</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$router</span>.<span class="title function_">push</span>(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;Describe&#x27;</span>,</span><br><span class="line">  <span class="attr">params</span>: &#123;</span><br><span class="line">    <span class="attr">id</span>: id</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 页面获取</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$route</span>.<span class="property">params</span>.<span class="property">id</span></span><br></pre></td></tr></table></figure><p>3.方案三</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 路由定义</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/describe&#x27;</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;Describe&#x27;</span>,</span><br><span class="line">  <span class="attr">component</span>: <span class="title class_">Describe</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 页面传参</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$router</span>.<span class="title function_">push</span>(&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/describe&#x27;</span>,</span><br><span class="line">    <span class="attr">query</span>: &#123;</span><br><span class="line">      <span class="attr">id</span>: id</span><br><span class="line">  <span class="string">`&#125;</span></span><br><span class="line"><span class="string">)</span></span><br><span class="line"><span class="string">// 页面获取</span></span><br><span class="line"><span class="string">this.$route.query.id</span></span><br></pre></td></tr></table></figure><p>4.三种方案对比 方案二参数不会拼接在路由后面,页面刷新参数会丢失 方案一和三参数拼接在后面,丑,而且暴露了信息</p><h2 id="3-14-Vue-observable"><a href="#3-14-Vue-observable" class="headerlink" title="3.14 Vue.observable"></a>3.14 Vue.observable</h2><p>2.6.0 新增 用法:让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象; 返回的对象可以直接用于渲染函数和计算属性内，并且会在发生改变时触发相应的更新; 也可以作为最小化的跨组件状态存储器，用于简单的场景。 通讯原理实质上是利用 Vue.observable 实现一个简易的 vuex</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">// 文件路径 - /store/store.js import Vue from &#x27;vue&#x27; export const store =</span><br><span class="line">Vue.observable(&#123; count: 0 &#125;) export const mutations = &#123; setCount (count) &#123;</span><br><span class="line">store.count = count &#125; &#125; //使用</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;label for=&quot;bookNum&quot;&gt;数 量&lt;/label&gt;</span><br><span class="line">    &lt;button @click=&quot;setCount(count + 1)&quot;&gt;+&lt;/button&gt;</span><br><span class="line">    &lt;span&gt;&#123;&#123; count &#125;&#125;&lt;/span&gt;</span><br><span class="line">    &lt;button @click=&quot;setCount(count - 1)&quot;&gt;-&lt;/button&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import &#123; store, mutations &#125; from &quot;../store/store&quot;; // Vue2.6新增API Observable</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &quot;Add&quot;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    count() &#123;</span><br><span class="line">      return store.count;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    setCount: mutations.setCount,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h1 id="4-render-函数"><a href="#4-render-函数" class="headerlink" title="4.render 函数"></a>4.render 函数</h1><p>1.场景:有些代码在 template 里面写会重复很多,所以这个时候 render 函数就有作用啦</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">// 根据 props 生成标签</span><br><span class="line">// 初级</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;div v-if=&quot;level === 1&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/div&gt;</span><br><span class="line">    &lt;p v-else-if=&quot;level === 2&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/p&gt;</span><br><span class="line">    &lt;h1 v-else-if=&quot;level === 3&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/h1&gt;</span><br><span class="line">    &lt;h2 v-else-if=&quot;level === 4&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/h2&gt;</span><br><span class="line">    &lt;strong v-else-if=&quot;level === 5&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/stong&gt;</span><br><span class="line">    &lt;textarea v-else-if=&quot;level === 6&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/textarea&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">// 优化版,利用 render 函数减小了代码重复率</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;child :level=&quot;level&quot;&gt;Hello world!&lt;/child&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script type=&#x27;text/javascript&#x27;&gt;</span><br><span class="line">  import Vue from &#x27;vue&#x27;</span><br><span class="line">  Vue.component(&#x27;child&#x27;, &#123;</span><br><span class="line">    render(h) &#123;</span><br><span class="line">      const tag = [&#x27;div&#x27;, &#x27;p&#x27;, &#x27;strong&#x27;, &#x27;h1&#x27;, &#x27;h2&#x27;, &#x27;textarea&#x27;][this.level-1]</span><br><span class="line">      return h(tag, this.$slots.default)</span><br><span class="line">    &#125;,</span><br><span class="line">    props: &#123;</span><br><span class="line">      level: &#123;  type: Number,  required: true  &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  export default &#123;</span><br><span class="line">    name: &#x27;hehe&#x27;,</span><br><span class="line">    data() &#123; return &#123; level: 3 &#125; &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>2.render 和 template 的对比 前者适合复杂逻辑,后者适合逻辑简单; 后者属于声明是渲染，前者属于自定 Render 函数; 前者的性能较高，后者性能较低。</p><h1 id="5-异步组件"><a href="#5-异步组件" class="headerlink" title="5.异步组件"></a>5.异步组件</h1><p>场景:项目过大就会导致加载缓慢,所以异步组件实现按需加载就是必须要做的事啦 1.异步注册组件 3 种方法</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 工厂函数执行 resolve 回调</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">component</span>(<span class="string">&quot;async-webpack-example&quot;</span>, <span class="keyword">function</span> (<span class="params">resolve</span>) &#123;</span><br><span class="line">  <span class="comment">// 这个特殊的 `require` 语法将会告诉 webpack</span></span><br><span class="line">  <span class="comment">// 自动将你的构建代码切割成多个包, 这些包</span></span><br><span class="line">  <span class="comment">// 会通过 Ajax 请求加载</span></span><br><span class="line">  <span class="built_in">require</span>([<span class="string">&quot;./my-async-component&quot;</span>], resolve);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 工厂函数返回 Promise</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">component</span>(</span><br><span class="line">  <span class="string">&quot;async-webpack-example&quot;</span>,</span><br><span class="line">  <span class="comment">// 这个 `import` 函数会返回一个 `Promise` 对象。</span></span><br><span class="line">  <span class="function">() =&gt;</span> <span class="keyword">import</span>(<span class="string">&quot;./my-async-component&quot;</span>)</span><br><span class="line">);</span><br><span class="line"><span class="comment">// 工厂函数返回一个配置化组件对象</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">AsyncComponent</span> = (<span class="params"></span>) =&gt; (&#123;</span><br><span class="line">  <span class="comment">// 需要加载的组件 (应该是一个 `Promise` 对象)</span></span><br><span class="line">  <span class="attr">component</span>: <span class="keyword">import</span>(<span class="string">&quot;./MyComponent.vue&quot;</span>),</span><br><span class="line">  <span class="comment">// 异步组件加载时使用的组件</span></span><br><span class="line">  <span class="attr">loading</span>: <span class="title class_">LoadingComponent</span>,</span><br><span class="line">  <span class="comment">// 加载失败时使用的组件</span></span><br><span class="line">  <span class="attr">error</span>: <span class="title class_">ErrorComponent</span>,</span><br><span class="line">  <span class="comment">// 展示加载时组件的延时时间。默认值是 200 (毫秒)</span></span><br><span class="line">  <span class="attr">delay</span>: <span class="number">200</span>,</span><br><span class="line">  <span class="comment">// 如果提供了超时时间且组件加载也超时了，</span></span><br><span class="line">  <span class="comment">// 则使用加载失败时使用的组件。默认值是：`Infinity`</span></span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">3000</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>异步组件的渲染本质上其实就是执行 2 次或者 2 次以上的渲染, 先把当前组件渲染为注释节点, 当组件加载成功后, 通过 forceRender 执行重新渲染。或者是渲染为注释节点, 然后再渲染为 loading 节点, 在渲染为请求完成的组件 2.路由的按需加载</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">webpack&lt; 2.4 时</span><br><span class="line">&#123;</span><br><span class="line">  path:&#x27;/&#x27;,</span><br><span class="line">  name:&#x27;home&#x27;,</span><br><span class="line">  components:resolve=&gt;require([&#x27;@/components/home&#x27;],resolve)</span><br><span class="line">&#125;</span><br><span class="line">webpack&gt; 2.4 时</span><br><span class="line">&#123;</span><br><span class="line">  path:&#x27;/&#x27;,</span><br><span class="line">  name:&#x27;home&#x27;,</span><br><span class="line">  components:()=&gt;import(&#x27;@/components/home&#x27;)</span><br><span class="line">&#125;</span><br><span class="line">import()方法由es6提出，import()方法是动态加载，返回一个Promise对象，then方法的参数是加载到的模块。类似于Node.js的require方法，主要import()方法是异步加载的。</span><br></pre></td></tr></table></figure><h1 id="6-动态组件"><a href="#6-动态组件" class="headerlink" title="6.动态组件"></a>6.动态组件</h1><p>场景:做一个 tab 切换时就会涉及到组件动态加载</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;component v-bind:is=&quot;currentTabComponent&quot;&gt;&lt;/component&gt;</span><br></pre></td></tr></table></figure><p>但是这样每次组件都会重新加载,会消耗大量性能,所以 就起到了作用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;keep-alive&gt;</span><br><span class="line">  &lt;component v-bind:is=&quot;currentTabComponent&quot;&gt;&lt;/component&gt;</span><br><span class="line">&lt;/keep-alive&gt;</span><br></pre></td></tr></table></figure><p>这样切换效果没有动画效果,这个也不用着急,可以利用内置的</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;transition&gt;</span><br><span class="line">&lt;keep-alive&gt;</span><br><span class="line">  &lt;component v-bind:is=&quot;currentTabComponent&quot;&gt;&lt;/component&gt;</span><br><span class="line">&lt;/keep-alive&gt;</span><br><span class="line">&lt;/transition&gt;</span><br></pre></td></tr></table></figure><h1 id="7-递归组件"><a href="#7-递归组件" class="headerlink" title="7.递归组件"></a>7.递归组件</h1><p>场景:如果开发一个 tree 组件,里面层级是根据后台数据决定的,这个时候就需要用到动态组件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">// 递归组件:</span><br><span class="line">组件在它的模板内可以递归的调用自己，只要给组件设置name组件就可以了。 //</span><br><span class="line">设置那么House在组件模板内就可以递归使用了,不过需要注意的是， //</span><br><span class="line">必须给一个条件来限制数量，否则会抛出错误: max stack size exceeded //</span><br><span class="line">组件递归用来开发一些具体有未知层级关系的独立组件。比如： // 联级选择器和树形控件</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div v-for=&quot;(item, index) in treeArr&quot;&gt;</span><br><span class="line">    子组件，当前层级值： &#123;&#123; index &#125;&#125; &lt;br /&gt;</span><br><span class="line">    &lt;!-- 递归调用自身, 后台判断是否不存在改值 --&gt;</span><br><span class="line">    &lt;tree :item=&quot;item.arr&quot; v-if=&quot;item.flag&quot;&gt;&lt;/tree&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  // 必须定义name，组件内部才能递归调用</span><br><span class="line">  name: &quot;tree&quot;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;&#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">  // 接收外部传入的值</span><br><span class="line">  props: &#123;</span><br><span class="line">    item: &#123;</span><br><span class="line">      type: Array,</span><br><span class="line">      default: () =&gt; [],</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>递归组件必须设置 name 和结束的阀值</p><h1 id="8-函数式组件"><a href="#8-函数式组件" class="headerlink" title="8.函数式组件"></a>8.函数式组件</h1><p>定义:无状态,无法实例化，内部没有任何生命周期处理方法 规则:在 2.3.0 之前的版本中，如果一个函数式组件想要接收 prop，则 props 选项是必须的。 在 2.3.0 或以上的版本中，你可以省略 props 选项，所有组件上的特性都会被自动隐式解析为 prop 在 2.5.0 及以上版本中，如果你使用了单文件组件(就是普通的.vue 文件),可以直接在 template 上声明 functional 组件需要的一切都是通过 context 参数传递<br>context 属性有: 1.props：提供所有 prop 的对象 2.children: VNode 子节点的数组 3.slots: 一个函数，返回了包含所有插槽的对象 4.scopedSlots: (2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。 5.data：传递给组件的整个数据对象，作为 createElement 的第二个参数传入组件 6.parent：对父组件的引用 7.listeners: (2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on 的一个别名。 8.injections: (2.3.0+) 如果使用了 inject 选项，则该对象包含了应当被注入的属性</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;template functional&gt;</span><br><span class="line">  &lt;div v-for=&quot;(item, index) in props.arr&quot;&gt;&#123;&#123; item &#125;&#125;&lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure><h1 id="9-components-和-Vue-component"><a href="#9-components-和-Vue-component" class="headerlink" title="9.components 和 Vue.component"></a>9.components 和 Vue.component</h1><p>components:局部注册组件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">components</span>: &#123; home &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Vue.component:全局注册组件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Vue</span>.<span class="title function_">component</span>(<span class="string">&quot;home&quot;</span>, home);</span><br></pre></td></tr></table></figure><h1 id="10-Vue-extend"><a href="#10-Vue-extend" class="headerlink" title="10.Vue.extend"></a>10.Vue.extend</h1><p>场景:vue 组件中有些需要将一些元素挂载到元素上,这个时候 extend 就起到作用了 是构造一个组件的语法器 写法:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建构造器</span></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">Profile</span> = <span class="title class_">Vue</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">  <span class="attr">template</span>: <span class="string">&quot;&lt;p&gt;&#123;&#123;extendData&#125;&#125;&lt;/br&gt;实例传入的数据为:&#123;&#123;propsExtend&#125;&#125;&lt;/p&gt;&quot;</span>, <span class="comment">//template对应的标签最外层必须只有一个标签</span></span><br><span class="line">  <span class="attr">data</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">extendData</span>: <span class="string">&quot;这是extend扩展的数据&quot;</span>,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">props</span>: [<span class="string">&quot;propsExtend&quot;</span>],</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 创建的构造器可以挂载到元素上,也可以通过 components 或 Vue.component()注册使用</span></span><br><span class="line"><span class="comment">// 挂载到一个元素上。可以通过propsData传参.</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Profile</span>(&#123; <span class="attr">propsData</span>: &#123; <span class="attr">propsExtend</span>: <span class="string">&quot;我是实例传入的数据&quot;</span> &#125; &#125;).$mount(</span><br><span class="line">  <span class="string">&quot;#app-extend&quot;</span></span><br><span class="line">);</span><br><span class="line"><span class="comment">// 通过 components 或 Vue.component()注册</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">component</span>(<span class="string">&quot;Profile&quot;</span>, <span class="title class_">Profile</span>);</span><br></pre></td></tr></table></figure><h1 id="11-mixins"><a href="#11-mixins" class="headerlink" title="11.mixins"></a>11.mixins</h1><p>场景:有些组件有些重复的 js 逻辑,如校验手机验证码,解析时间等,mixins 就可以实现这种混入 mixins 值是一个数组</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> mixin = &#123;</span><br><span class="line">  <span class="title function_">created</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">dealTime</span>();</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="title function_">dealTime</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;这是mixin的dealTime里面的方法&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">mixins</span>: [mixin],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="12-extends"><a href="#12-extends" class="headerlink" title="12.extends"></a>12.extends</h1><p>extends 用法和 mixins 很相似,只不过接收的参数是简单的选项对象或构造函数,所以 extends 只能单次扩展一个组件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> extend = &#123;</span><br><span class="line">  <span class="title function_">created</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">dealTime</span>();</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="title function_">dealTime</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;这是mixin的dealTime里面的方法&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">extends</span>: extend,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="13-Vue-use"><a href="#13-Vue-use" class="headerlink" title="13.Vue.use()"></a>13.Vue.use()</h1><p>场景:我们使用 element 时会先 import,再 Vue.use()一下,实际上就是注册组件,触发 install 方法; 这个在组件调用会经常使用到; 会自动组织多次注册相同的插件.</p><h1 id="14-install"><a href="#14-install" class="headerlink" title="14.install"></a>14.install</h1><p>场景:在 Vue.use()说到,执行该方法会触发 install 是开发 vue 的插件,这个方法的第一个参数是 Vue 构造器，第二个参数是一个可选的选项对象(可选)</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> <span class="title class_">MyPlugin</span> = &#123;&#125;;</span><br><span class="line"><span class="title class_">MyPlugin</span>.<span class="property">install</span> = <span class="keyword">function</span> (<span class="params">Vue, options</span>) &#123;</span><br><span class="line">  <span class="comment">// 2. 添加全局资源,第二个参数传一个值默认是update对应的值</span></span><br><span class="line">  <span class="title class_">Vue</span>.<span class="title function_">directive</span>(<span class="string">&quot;click&quot;</span>, &#123;</span><br><span class="line">    <span class="title function_">bind</span>(<span class="params">el, binding, vnode, oldVnode</span>) &#123;</span><br><span class="line">      <span class="comment">//做绑定的准备工作,添加时间监听</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;指令my-directive的bind执行啦&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">inserted</span>: <span class="keyword">function</span> (<span class="params">el</span>) &#123;</span><br><span class="line">      <span class="comment">//获取绑定的元素</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;指令my-directive的inserted执行啦&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">update</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="comment">//根据获得的新值执行对应的更新</span></span><br><span class="line">      <span class="comment">//对于初始值也会调用一次</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;指令my-directive的update执行啦&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">componentUpdated</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;指令my-directive的componentUpdated执行啦&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">unbind</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="comment">//做清理操作</span></span><br><span class="line">      <span class="comment">//比如移除bind时绑定的事件监听器</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;指令my-directive的unbind执行啦&quot;</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="comment">// 3. 注入组件</span></span><br><span class="line">  <span class="title class_">Vue</span>.<span class="title function_">mixin</span>(&#123;</span><br><span class="line">    <span class="attr">created</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;注入组件的created被调用啦&quot;</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;options的值为&quot;</span>, options);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="comment">// 4. 添加实例方法</span></span><br><span class="line">  <span class="title class_">Vue</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">$myMethod</span> = <span class="keyword">function</span> (<span class="params">methodOptions</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;实例方法myMethod被调用啦&quot;</span>);</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//调用MyPlugin</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">use</span>(<span class="title class_">MyPlugin</span>, &#123; <span class="attr">someOption</span>: <span class="literal">true</span> &#125;);</span><br><span class="line"><span class="comment">//3.挂载</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span><br><span class="line">  <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>更多请戳 vue 中 extend，mixins，extends，components,install 的几个操作</p><h1 id="15-Vue-nextTick"><a href="#15-Vue-nextTick" class="headerlink" title="15. Vue.nextTick"></a>15. Vue.nextTick</h1><p>2.1.0 新增 场景:页面加载时需要让文本框获取焦点 用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span><br><span class="line"><span class="comment">//因为 mounted 阶段 dom 并未渲染完毕,所以需要$nextTick</span></span><br><span class="line">  <span class="variable language_">this</span>.$nextTick(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">$refs</span>.<span class="property">inputs</span>.<span class="title function_">focus</span>() <span class="comment">//通过 $refs 获取dom 并绑定 focus 方法</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="16-Vue-directive"><a href="#16-Vue-directive" class="headerlink" title="16.Vue.directive"></a>16.Vue.directive</h1><h2 id="16-1-使用"><a href="#16-1-使用" class="headerlink" title="16.1 使用"></a>16.1 使用</h2><p>场景:官方给我们提供了很多指令,但是我们如果想将文字变成指定的颜色定义成指令使用,这个时候就需要用到 Vue.directive</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">// 全局定义 Vue.directive(&quot;change-color&quot;,function(el,binding,vnode)&#123;</span><br><span class="line">el.style[&quot;color&quot;]= binding.value; &#125;) // 使用</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div v-change-color=&quot;“color”&quot;&gt;&#123;&#123; message &#125;&#125;&lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      color: &quot;green&quot;,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="16-2-生命周期"><a href="#16-2-生命周期" class="headerlink" title="16.2 生命周期"></a>16.2 生命周期</h2><p>1.bind 只调用一次，指令第一次绑定到元素时候调用，用这个钩子可以定义一个绑定时执行一次的初始化动作。 2.inserted:被绑定的元素插入父节点的时候调用(父节点存在即可调用，不必存在 document 中) 3.update: 被绑定与元素所在模板更新时调用，而且无论绑定值是否有变化，通过比较更新前后的绑定值，忽略不必要的模板更新 4.componentUpdate :被绑定的元素所在模板完成一次更新更新周期的时候调用 5.unbind: 只调用一次，指令月元素解绑的时候调用</p><h1 id="17-Vue-filter"><a href="#17-Vue-filter" class="headerlink" title="17. Vue.filter"></a>17. Vue.filter</h1><p>场景:时间戳转化成年月日这是一个公共方法,所以可以抽离成过滤器使用</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用</span></span><br><span class="line"><span class="comment">// 在双花括号中</span></span><br><span class="line">&#123;</span><br><span class="line">  &#123;</span><br><span class="line">    message | capitalize;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 在 `v-bind` 中</span></span><br><span class="line">&lt;div v-<span class="attr">bind</span>:id=<span class="string">&quot;rawId | formatId&quot;</span>&gt;&lt;/div&gt;;</span><br><span class="line"><span class="comment">// 全局注册</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">filter</span>(<span class="string">&quot;stampToYYMMDD&quot;</span>, <span class="function">(<span class="params">value</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 处理逻辑</span></span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 局部注册</span></span><br><span class="line"><span class="attr">filters</span>: &#123;</span><br><span class="line">  <span class="attr">stampToYYMMDD</span>: <span class="function">(<span class="params">value</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 处理逻辑</span></span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 多个过滤器全局注册</span></span><br><span class="line"><span class="comment">// /src/common/filters.js</span></span><br><span class="line"><span class="keyword">let</span> <span class="title function_">dateServer</span> = (<span class="params">value</span>) =&gt; value.<span class="title function_">replace</span>(<span class="regexp">/(\d&#123;4&#125;)(\d&#123;2&#125;)(\d&#123;2&#125;)/g</span>, <span class="string">&quot;$1-$2-$3&quot;</span>);</span><br><span class="line"><span class="keyword">export</span> &#123; dateServer &#125;;</span><br><span class="line"><span class="comment">// /src/main.js</span></span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> custom <span class="keyword">from</span> <span class="string">&quot;./common/filters/custom&quot;</span>;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">keys</span>(custom).<span class="title function_">forEach</span>(<span class="function">(<span class="params">key</span>) =&gt;</span> <span class="title class_">Vue</span>.<span class="title function_">filter</span>(key, custom[key]));</span><br></pre></td></tr></table></figure><h1 id="18-Vue-compile"><a href="#18-Vue-compile" class="headerlink" title="18.Vue.compile"></a>18.Vue.compile</h1><p>场景:在 render 函数中编译模板字符串。只在独立构建时有效</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> res = <span class="title class_">Vue</span>.<span class="title function_">compile</span>(<span class="string">&quot;&lt;div&gt;&lt;span&gt;&#123;&#123; msg &#125;&#125;&lt;/span&gt;&lt;/div&gt;&quot;</span>);</span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span><br><span class="line">  <span class="attr">data</span>: &#123;</span><br><span class="line">    <span class="attr">msg</span>: <span class="string">&quot;hello&quot;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">render</span>: res.<span class="property">render</span>,</span><br><span class="line">  <span class="attr">staticRenderFns</span>: res.<span class="property">staticRenderFns</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h1 id="19-Vue-version"><a href="#19-Vue-version" class="headerlink" title="19.Vue.version"></a>19.Vue.version</h1><p>场景:有些开发插件需要针对不同 vue 版本做兼容,所以就会用到 Vue.version 用法:Vue.version()可以获取 vue 版本</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> version = <span class="title class_">Number</span>(<span class="title class_">Vue</span>.<span class="property">version</span>.<span class="title function_">split</span>(<span class="string">&quot;.&quot;</span>)[<span class="number">0</span>]);</span><br><span class="line"><span class="keyword">if</span> (version === <span class="number">2</span>) &#123;</span><br><span class="line">  <span class="comment">// Vue v2.x.x</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (version === <span class="number">1</span>) &#123;</span><br><span class="line">  <span class="comment">// Vue v1.x.x</span></span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="comment">// Unsupported versions of Vue</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="20-Vue-set"><a href="#20-Vue-set" class="headerlink" title="20.Vue.set()"></a>20.Vue.set()</h1><p>场景:当你利用索引直接设置一个数组项时或你修改数组的长度时,由于 Object.defineprototype()方法限制,数据不响应式更新 不过 vue.3.x 将利用 proxy 这个问题将得到解决 解决方案:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// 利用 set</span><br><span class="line">this.$set(arr,index,item)</span><br><span class="line">// 利用数组 push(),splice()</span><br></pre></td></tr></table></figure><h1 id="21-Vue-config-keyCodes"><a href="#21-Vue-config-keyCodes" class="headerlink" title="21.Vue.config.keyCodes"></a>21.Vue.config.keyCodes</h1><p>场景:自定义按键修饰符别名</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 将键码为 113 定义为 f2 Vue.config.keyCodes.f2 = 113;</span><br><span class="line">&lt;input type=&quot;text&quot; @keyup.f2=&quot;add&quot; /&gt;</span><br></pre></td></tr></table></figure><h1 id="22-Vue-config-performance"><a href="#22-Vue-config-performance" class="headerlink" title="22.Vue.config.performance"></a>22.Vue.config.performance</h1><p>场景:监听性能</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Vue</span>.<span class="property">config</span>.<span class="property">performance</span> = <span class="literal">true</span>;</span><br></pre></td></tr></table></figure><p>只适用于开发模式和支持 performance.mark API 的浏览器上</p><h1 id="23-Vue-config-errorHandler"><a href="#23-Vue-config-errorHandler" class="headerlink" title="23.Vue.config.errorHandler"></a>23.Vue.config.errorHandler</h1><p>1.场景:指定组件的渲染和观察期间未捕获错误的处理函数 2.规则: 从 2.2.0 起，这个钩子也会捕获组件生命周期钩子里的错误。同样的，当这个钩子是 undefined 时，被捕获的错误会通过 console.error 输出而避免应用崩溃 从 2.4.0 起，这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了 从 2.6.0 起，这个钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外，如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数)，则来自其 Promise 链的错误也会被处理 3.使用</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Vue</span>.<span class="property">config</span>.<span class="property">errorHandler</span> = <span class="keyword">function</span> (<span class="params">err, vm, info</span>) &#123;</span><br><span class="line">  <span class="comment">// handle error</span></span><br><span class="line">  <span class="comment">// `info` 是 Vue 特定的错误信息，比如错误所在的生命周期钩子</span></span><br><span class="line">  <span class="comment">// 只在 2.2.0+ 可用</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="24-Vue-config-warnHandler"><a href="#24-Vue-config-warnHandler" class="headerlink" title="24.Vue.config.warnHandler"></a>24.Vue.config.warnHandler</h1><p>2.4.0 新增 1.场景:为 Vue 的运行时警告赋予一个自定义处理函数,只会在开发者环境下生效 2.用法:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Vue</span>.<span class="property">config</span>.<span class="property">warnHandler</span> = <span class="keyword">function</span> (<span class="params">msg, vm, trace</span>) &#123;</span><br><span class="line">  <span class="comment">// `trace` 是组件的继承关系追踪</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="25-v-pre"><a href="#25-v-pre" class="headerlink" title="25.v-pre"></a>25.v-pre</h1><p>场景:vue 是响应式系统,但是有些静态的标签不需要多次编译,这样可以节省性能</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;span v-pre&gt;&#123;&#123; this will not be compiled &#125;&#125;&lt;/span&gt;</span><br><span class="line">显示的是&#123;&#123; this will not be compiled &#125;&#125;</span><br><span class="line">&lt;span v-pre&gt;&#123;&#123;msg&#125;&#125;&lt;/span&gt;</span><br><span class="line">即使data里面定义了msg这里仍然是显示的&#123;&#123; msg &#125;&#125;</span><br></pre></td></tr></table></figure><h1 id="26-v-cloak"><a href="#26-v-cloak" class="headerlink" title="26.v-cloak"></a>26.v-cloak</h1><p>场景:在网速慢的情况下,在使用 vue 绑定数据的时候，渲染页面时会出现变量闪烁 用法:这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时，这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">// template 中</span><br><span class="line">&lt;div class=&quot;#app&quot; v-cloak&gt;</span><br><span class="line">    &lt;p&gt;&#123;&#123;value.name&#125;&#125;&lt;/p&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">// css 中 [v-cloak] &#123; display: none; &#125;</span><br></pre></td></tr></table></figure><p>这样就可以解决闪烁,但是会出现白屏,这样可以结合骨架屏使用</p><h1 id="27-v-once"><a href="#27-v-once" class="headerlink" title="27.v-once"></a>27.v-once</h1><p>场景:有些 template 中的静态 dom 没有改变,这时就只需要渲染一次,可以降低性能开销</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;span v-once&gt; 这时只需要加载一次的标签&lt;/span&gt;</span><br></pre></td></tr></table></figure><p>v-once 和 v-pre 的区别: v-once 只渲染一次；v-pre 不编译,原样输出</p><h1 id="28-事件修饰符"><a href="#28-事件修饰符" class="headerlink" title="28.事件修饰符"></a>28.事件修饰符</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.stop:阻止冒泡</span><br><span class="line">.prevent:阻止默认行为</span><br><span class="line">.self:仅绑定元素自身触发</span><br><span class="line">.once: 2.1.4 新增,只触发一次</span><br><span class="line">.passive: 2.3.0 新增,滚动事件的默认行为 (即滚动行为) 将会立即触发,不能和.prevent 一起使用</span><br></pre></td></tr></table></figure><h1 id="29-按键修饰符和按键码"><a href="#29-按键修饰符和按键码" class="headerlink" title="29.按键修饰符和按键码"></a>29.按键修饰符和按键码</h1><p>场景:有的时候需要监听键盘的行为,如按下 enter 去查询接口等</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// 对应键盘上的关键字</span><br><span class="line">.enter</span><br><span class="line">.tab</span><br><span class="line">.delete (捕获“删除”和“退格”键)</span><br><span class="line">.esc</span><br><span class="line">.space</span><br><span class="line">.up</span><br><span class="line">.down</span><br><span class="line">.left</span><br><span class="line">.right</span><br></pre></td></tr></table></figure><h1 id="30-Vue-router"><a href="#30-Vue-router" class="headerlink" title="30.Vue-router"></a>30.Vue-router</h1><p>场景:Vue-router 是官方提供的路由插件</p><h2 id="30-1-缓存和动画"><a href="#30-1-缓存和动画" class="headerlink" title="30.1 缓存和动画"></a>30.1 缓存和动画</h2><p>1.路由是使用官方组件 vue-router,使用方法相信大家非常熟悉; 2.这里我就叙述下路由的缓存和动画; 3.可以用 exclude(除了)或者 include(包括),2.1.0 新增来坐判断</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;transition&gt;</span><br><span class="line">  &lt;keep-alive :include=&quot;[&#x27;a&#x27;, &#x27;b&#x27;]&quot;&gt;</span><br><span class="line">  //或include=&quot;a,b&quot; :include=&quot;/a|b/&quot;,a 和 b 表示组件的 name</span><br><span class="line">  //因为有些页面,如试试数据统计,要实时刷新,所以就不需要缓存</span><br><span class="line">    &lt;router-view/&gt; //路由标签</span><br><span class="line">  &lt;/keep-alive&gt;</span><br><span class="line">  &lt;router-view exclude=&quot;c&quot;/&gt; </span><br><span class="line">  // c 表示组件的 name值</span><br><span class="line">&lt;/transition&gt;</span><br></pre></td></tr></table></figure><p>注:匹配首先检查组件自身的 name 选项，如果 name 选项不可用，则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配 4.用 v-if 做判断,组件会重新渲染,但是不用一一列举组件 name</p><h2 id="30-2-全局路由钩子"><a href="#30-2-全局路由钩子" class="headerlink" title="30.2 全局路由钩子"></a>30.2 全局路由钩子</h2><p>1.router.beforeEach</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">router.<span class="title function_">beforeEach</span>(<span class="function">(<span class="params">to, <span class="keyword">from</span>, next</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;全局前置守卫：beforeEach -- next需要调用&quot;</span>); <span class="comment">//一般登录拦截用这个,也叫导航钩子守卫</span></span><br><span class="line">  <span class="keyword">if</span> (path === <span class="string">&quot;/login&quot;</span>) &#123;</span><br><span class="line">    <span class="title function_">next</span>();</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (token) &#123;</span><br><span class="line">    <span class="title function_">next</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>2.router.beforeResolve (v 2.5.0+) 和 beforeEach 类似，区别是在导航被确认之前，同时在所有组件内守卫和异步路由组件被解析之后，解析守卫就被调用 即在 beforeEach 之后调用<br>3.router.afterEach 全局后置钩子 在所有路由跳转结束的时候调用 这些钩子不会接受 next 函数也不会改变导航本身</p><h2 id="30-3-组件路由钩子"><a href="#30-3-组件路由钩子" class="headerlink" title="30.3 组件路由钩子"></a>30.3 组件路由钩子</h2><p>1.beforeRouteEnter 在渲染该组件的对应路由被确认前调用，用法和参数与 router.beforeEach 类似，next 需要被主动调用 此时组件实例还未被创建，不能访问 this 可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调，并且把组件实例作为回调方法的参数</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">beforeRouteEnter</span> (to, <span class="keyword">from</span>, next) &#123;</span><br><span class="line">  <span class="comment">// 这里还无法访问到组件实例，this === undefined</span></span><br><span class="line">  <span class="title function_">next</span>( <span class="function"><span class="params">vm</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 通过 `vm` 访问组件实例</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>2.beforeRouteUpdate (v 2.2+) 在当前路由改变，并且该组件被复用时调用，可以通过 this 访问实例， next 需要被主动调用，不能传回调<br>3.beforeRouteLeave 导航离开该组件的对应路由时调用，可以访问组件实例 this，next 需要被主动调用，不能传回调</p><h2 id="30-4-路由模式"><a href="#30-4-路由模式" class="headerlink" title="30.4 路由模式"></a>30.4 路由模式</h2><p>设置 mode 属性:hash 或 history</p><h2 id="30-5-Vue-router"><a href="#30-5-Vue-router" class="headerlink" title="30.5 Vue.$router"></a>30.5 Vue.$router</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">this.$router.push():跳转到不同的url，但这个方法回向history栈添加一个记录，点击后退会返回到上一个页面</span><br><span class="line">this.$router.replace():不会有记录</span><br><span class="line">this.$router.go(n):n可为正数可为负数。正数返回上一个页面,类似 window.history.go(n)</span><br></pre></td></tr></table></figure><h2 id="30-6-Vue-route"><a href="#30-6-Vue-route" class="headerlink" title="30.6 Vue.$route"></a>30.6 Vue.$route</h2><p>表示当前跳转的路由对象,属性有: name:路由名称 path:路径 query:传参接收值 params:传参接收值 fullPath:完成解析后的 URL，包含查询参数和 hash 的完整路径 matched:路由记录副本 redirectedFrom:如果存在重定向，即为重定向来源的路由的名字</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">this.$route.params.id:获取通过 params 或/:id传参的参数</span><br><span class="line">this.$route.query.id:获取通过 query 传参的参数</span><br></pre></td></tr></table></figure><h2 id="30-7-router-view-的-key"><a href="#30-7-router-view-的-key" class="headerlink" title="30.7 router-view 的 key"></a>30.7 router-view 的 key</h2><p>场景:由于 Vue 会复用相同组件, 即 &#x2F;page&#x2F;1 &#x3D;&gt; &#x2F;page&#x2F;2 或者 &#x2F;page?id&#x3D;1 &#x3D;&gt; &#x2F;page?id&#x3D;2 这类链接跳转时, 将不在执行 created, mounted 之类的钩子</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-view :key=&quot;$route.fullPath&quot;&gt;&lt;/router-view&gt;</span><br></pre></td></tr></table></figure><p>这样组件的 created 和 mounted 就都会执行</p><h1 id="31-Object-freeze"><a href="#31-Object-freeze" class="headerlink" title="31.Object.freeze"></a>31.Object.freeze</h1><p>场景:一个长列表数据,一般不会更改,但是 vue 会做 getter 和 setter 的转换 用法:是 ES5 新增的特性，可以冻结一个对象，防止对象被修改 支持:vue 1.0.18+对其提供了支持，对于 data 或 vuex 里使用 freeze 冻结了的对象，vue 不会做 getter 和 setter 的转换 注意:冻结只是冻结里面的单个属性,引用地址还是可以更改</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span><br><span class="line">  <span class="attr">data</span>: &#123;</span><br><span class="line">    <span class="comment">// vue不会对list里的object做getter、setter绑定</span></span><br><span class="line">    <span class="attr">list</span>: <span class="title class_">Object</span>.<span class="title function_">freeze</span>([&#123; <span class="attr">value</span>: <span class="number">1</span> &#125;, &#123; <span class="attr">value</span>: <span class="number">2</span> &#125;]),</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">mounted</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// 界面不会有响应,因为单个属性被冻结</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">list</span>[<span class="number">0</span>].<span class="property">value</span> = <span class="number">100</span>;</span><br><span class="line">    <span class="comment">// 下面两种做法，界面都会响应</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">list</span> = [&#123; <span class="attr">value</span>: <span class="number">100</span> &#125;, &#123; <span class="attr">value</span>: <span class="number">200</span> &#125;];</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">list</span> = <span class="title class_">Object</span>.<span class="title function_">freeze</span>([&#123; <span class="attr">value</span>: <span class="number">100</span> &#125;, &#123; <span class="attr">value</span>: <span class="number">200</span> &#125;]);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h1 id="32-调试-template"><a href="#32-调试-template" class="headerlink" title="32.调试 template"></a>32.调试 template</h1><p>场景:在 Vue 开发过程中, 经常会遇到 template 模板渲染时 JavaScript 变量出错的问题, 此时也许你会通过 console.log 来进行调试 这时可以在开发环境挂载一个 log 函数</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// main.js Vue.prototype.$log = window.console.log; // 组件内部</span><br><span class="line">&lt;div&gt;&#123;&#123;$log(info)&#125;&#125;&lt;/div&gt;</span><br></pre></td></tr></table></figure><h1 id="33-vue-loader-小技巧"><a href="#33-vue-loader-小技巧" class="headerlink" title="33.vue-loader 小技巧"></a>33.vue-loader 小技巧</h1><h2 id="33-1-preserveWhitespace"><a href="#33-1-preserveWhitespace" class="headerlink" title="33.1 preserveWhitespace"></a>33.1 preserveWhitespace</h2><p>场景:开发 vue 代码一般会有空格,这个时候打包压缩如果不去掉空格会加大包的体积 配置 preserveWhitespace 可以减小包的体积</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;vue&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;preserveWhitespace&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="33-2-transformToRequire"><a href="#33-2-transformToRequire" class="headerlink" title="33.2 transformToRequire"></a>33.2 transformToRequire</h2><p>场景:以前在写 Vue 的时候经常会写到这样的代码：把图片提前 require 传给一个变量再传给组件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">// page 代码</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;avatar :img-src=&quot;imgSrc&quot;&gt;&lt;/avatar&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.imgSrc = require(&quot;./assets/default-avatar.png&quot;);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>现在:通过配置 transformToRequire 后，就可以直接配置，这样 vue-loader 会把对应的属性自动 require 之后传给组件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vue-cli 2.x在vue-loader.conf.js 默认配置是</span></span><br><span class="line"><span class="attr">transformToRequire</span>: &#123;</span><br><span class="line">    <span class="attr">video</span>: [<span class="string">&#x27;src&#x27;</span>, <span class="string">&#x27;poster&#x27;</span>],</span><br><span class="line">    <span class="attr">source</span>: <span class="string">&#x27;src&#x27;</span>,</span><br><span class="line">    <span class="attr">img</span>: <span class="string">&#x27;src&#x27;</span>,</span><br><span class="line">    <span class="attr">image</span>: <span class="string">&#x27;xlink:href&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 配置文件,如果是vue-cli2.x 在vue-loader.conf.js里面修改</span></span><br><span class="line">  <span class="attr">avatar</span>: [<span class="string">&#x27;default-src&#x27;</span>]</span><br><span class="line"><span class="comment">// vue-cli 3.x 在vue.config.js</span></span><br><span class="line"><span class="comment">// vue-cli 3.x 将transformToRequire属性换为了transformAssetUrls</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">  pages,</span><br><span class="line">  <span class="attr">chainWebpack</span>: <span class="function"><span class="params">config</span> =&gt;</span> &#123;</span><br><span class="line">    config</span><br><span class="line">      .<span class="property">module</span></span><br><span class="line">        .<span class="title function_">rule</span>(<span class="string">&#x27;vue&#x27;</span>)</span><br><span class="line">        .<span class="title function_">use</span>(<span class="string">&#x27;vue-loader&#x27;</span>)</span><br><span class="line">        .<span class="title function_">loader</span>(<span class="string">&#x27;vue-loader&#x27;</span>)</span><br><span class="line">        .<span class="title function_">tap</span>(<span class="function"><span class="params">options</span> =&gt;</span> &#123;</span><br><span class="line">      options.<span class="property">transformAssetUrls</span> = &#123;</span><br><span class="line">        <span class="attr">avatar</span>: <span class="string">&#x27;img-src&#x27;</span>,</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> options;</span><br><span class="line">      &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// page 代码可以简化为</span></span><br><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">avatar</span> <span class="attr">img-src</span>=<span class="string">&quot;./assets/default-avatar.png&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">avatar</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure><h1 id="34-为路径设置别名"><a href="#34-为路径设置别名" class="headerlink" title="34.为路径设置别名"></a>34.为路径设置别名</h1><p>1.场景:在开发过程中，我们经常需要引入各种文件，如图片、CSS、JS 等，为了避免写很长的相对路径（..&#x2F;），我们可以为不同的目录配置一个别名<br>2.vue-cli 2.x 配置</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在 webpack.base.config.js中的 resolve 配置项，在其 alias 中增加别名</span></span><br><span class="line"><span class="attr">resolve</span>: &#123;</span><br><span class="line">    <span class="attr">extensions</span>: [<span class="string">&#x27;.js&#x27;</span>, <span class="string">&#x27;.vue&#x27;</span>, <span class="string">&#x27;.json&#x27;</span>],</span><br><span class="line">    <span class="attr">alias</span>: &#123;</span><br><span class="line">      <span class="string">&#x27;vue$&#x27;</span>: <span class="string">&#x27;vue/dist/vue.esm.js&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;@&#x27;</span>: <span class="title function_">resolve</span>(<span class="string">&#x27;src&#x27;</span>),</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>3.vue-cli 3.x 配置</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在根目录下创建vue.config.js</span></span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">&quot;path&quot;</span>);</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">resolve</span>(<span class="params">dir</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(__dirname);</span><br><span class="line">  <span class="keyword">return</span> path.<span class="title function_">join</span>(__dirname, dir);</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">  <span class="attr">chainWebpack</span>: <span class="function">(<span class="params">config</span>) =&gt;</span> &#123;</span><br><span class="line">    config.<span class="property">resolve</span>.<span class="property">alias</span>.<span class="title function_">set</span>(key, value); <span class="comment">// key,value自行定义，比如.set(&#x27;@@&#x27;, resolve(&#x27;src/components&#x27;))</span></span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="35-img-加载失败"><a href="#35-img-加载失败" class="headerlink" title="35.img 加载失败"></a>35.img 加载失败</h1><p>场景:有些时候后台返回图片地址不一定能打开,所以这个时候应该加一张默认图片</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">// page 代码</span><br><span class="line">&lt;img :src=&quot;imgUrl&quot; @error=&quot;handleError&quot; alt=&quot;&quot;&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default&#123;</span><br><span class="line">  data()&#123;</span><br><span class="line">    return&#123;</span><br><span class="line">      imgUrl:&#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods:&#123;</span><br><span class="line">    handleError(e)&#123;</span><br><span class="line">      e.target.src=reqiure(&#x27;图片路径&#x27;) //当然如果项目配置了transformToRequire,参考上面 27.2</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h1 id="36-css"><a href="#36-css" class="headerlink" title="36.css"></a>36.css</h1><h2 id="36-1-局部样式"><a href="#36-1-局部样式" class="headerlink" title="36.1 局部样式"></a>36.1 局部样式</h2><p>1.Vue 中 style 标签的 scoped 属性表示它的样式只作用于当前模块，是样式私有化. 2.渲染的规则&#x2F;原理： 给 HTML 的 DOM 节点添加一个 不重复的 data 属性 来表示 唯一性 在对应的 CSS 选择器 末尾添加一个当前组件的 data 属性选择器来私有化样式，如：.demo[data-v-2311c06a]{} 如果引入 less 或 sass 只会在最后一个元素上设置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">// 原始代码</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;demo&quot;&gt;</span><br><span class="line">    &lt;span class=&quot;content&quot;&gt; Vue.js scoped &lt;/span&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">.demo &#123;</span><br><span class="line">  font-size: 16px;</span><br><span class="line">  .content &#123;</span><br><span class="line">    color: red;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line">// 浏览器渲染效果</span><br><span class="line">&lt;div data-v-fed36922&gt;</span><br><span class="line">  Vue.js scoped</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;style type=&quot;text/css&quot;&gt;</span><br><span class="line">.demo[data-v-039c5b43] &#123;</span><br><span class="line">  font-size: 14px;</span><br><span class="line">&#125;</span><br><span class="line">.demo .content[data-v-039c5b43] &#123;</span><br><span class="line">  //.demo 上并没有加 data 属性</span><br><span class="line">  color: red;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="36-2-deep-属性"><a href="#36-2-deep-属性" class="headerlink" title="36.2 deep 属性"></a>36.2 deep 属性</h2><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><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">// 上面样式加一个 /deep/</span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">  <span class="selector-class">.demo</span>&#123;</span><br><span class="line">    <span class="attribute">font-size</span>: <span class="number">14px</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="selector-class">.demo</span> /deep/ <span class="selector-class">.content</span>&#123;</span><br><span class="line">    <span class="attribute">color</span>: blue;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line">// 浏览器编译后</span><br><span class="line">&lt;style type=&quot;<span class="selector-tag">text</span>/css&quot;&gt;</span><br><span class="line"><span class="selector-class">.demo</span><span class="selector-attr">[data-v-039c5b43]</span> &#123;</span><br><span class="line">  <span class="attribute">font-size</span>: <span class="number">14px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.demo</span><span class="selector-attr">[data-v-039c5b43]</span> <span class="selector-class">.content</span> &#123;</span><br><span class="line">  <span class="attribute">color</span>: blue;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;Vue开发技巧&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Spring-Cloud之注册中心Eureka</title>
    <link href="http://next.skyheng.com/post/24915.html"/>
    <id>http://next.skyheng.com/post/24915.html</id>
    <published>2020-06-04T01:52:54.000Z</published>
    <updated>2025-11-30T14:41:25.871Z</updated>
    
    <content type="html"><![CDATA[<p>Eureka是Netflix开源的一款提供服务注册和发现的产品，它提供了完整的Service Registry和Service Discovery实现。也是springcloud体系中最重要最核心的组件之一。</p><span id="more"></span><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p><img data-src="/../../images/2020-06-04.Spring-Cloud%E4%B9%8B%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83Eureka/20191213113045.png" alt="20191213113045"></p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><h2 id="案例实践"><a href="#案例实践" class="headerlink" title="案例实践"></a>案例实践</h2><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><h2 id="集群"><a href="#集群" class="headerlink" title="集群"></a>集群</h2>]]></content>
    
    
    <summary type="html">&lt;p&gt;Eureka是Netflix开源的一款提供服务注册和发现的产品，它提供了完整的Service Registry和Service Discovery实现。也是springcloud体系中最重要最核心的组件之一。&lt;/p&gt;</summary>
    
    
    
    <category term="java" scheme="http://next.skyheng.com/categories/java/"/>
    
    <category term="springCloud" scheme="http://next.skyheng.com/categories/java/springCloud/"/>
    
    
    <category term="java" scheme="http://next.skyheng.com/tags/java/"/>
    
    <category term="springCloud" scheme="http://next.skyheng.com/tags/springCloud/"/>
    
  </entry>
  
  <entry>
    <title>Oracle数据库开发使用记录</title>
    <link href="http://next.skyheng.com/post/37916.html"/>
    <id>http://next.skyheng.com/post/37916.html</id>
    <published>2020-06-04T01:40:43.000Z</published>
    <updated>2025-11-30T14:41:25.910Z</updated>
    
    <content type="html"><![CDATA[<p>Oracle 数据库使用很久了，但是使用过程中出现的一些问题从来在也没有记录、每次出现同样的问题使用时又忘记了，又要搜索资料查询、浪费时间、so! 还是写个笔记记录下吧</p><span id="more"></span><h2 id="oracle修改字段精度"><a href="#oracle修改字段精度" class="headerlink" title="oracle修改字段精度"></a>oracle修改字段精度</h2><p> 我们在设计数据库时难免会因为最初的需求导致数据库字段的设置不能满足实际的需求，如果我们是在新建之初表内无数据时我们可以直接重新建，但是如果有数据时就难免会遇到一些其他问题，例如我们修改数值型的精度时，如果我们是想将精度调小，可以直接实现，如果把精度调大会弹出请清空字段内容后重试的提示。</p><p>有一个表名为 <code>tb_test</code>，字段段名为<code>n_max_prpt</code>，数据类型<code>nchar(20)</code>。</p><p>1、假设字段数据为空，则不管改为什么字段类型，可以直接执行：<br><code>alter table tb_test modify (name nvarchar2(20));</code></p><p>2、假设字段有数据，则改为<code>nvarchar2(20)</code>可以直接执行：<br><code>alter table tb_test modify (name nvarchar2(20));</code></p><p>3、假设字段有数据，则改为<code>varchar2(40)</code>执行时会弹出：“ORA-01439:要更改数据类型,则要修改的列必须为空”，这时要用下面方法来解决这个问题：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">--修改原字段名n_max_prpt为n_max_prpt_tmp</span><br><span class="line">alter table tb_test rename column n_max_prpt to n_max_prpt_tmp;</span><br><span class="line">--增加一个和原字段名同名的字段n_max_prpt</span><br><span class="line">alter table tb_test add n_max_prpt NUMBER(20,6);</span><br><span class="line">comment on column tb_test.n_max_prpt is &#x27;中介协议手续费率&#x27;;</span><br><span class="line">--将原字段n_max_prpt_tmp数据更新到增加的字段n_max_prpt</span><br><span class="line">update tb_test set n_max_prpt = trim(n_max_prpt_tmp);</span><br><span class="line">--更新完，删除原字段n_max_prpt_tmp</span><br><span class="line">alter table tb_test drop column n_max_prpt_tmp;</span><br></pre></td></tr></table></figure><p>总结：<br>1、当字段没有数据或者要修改的新类型和原类型兼容时，可以直接modify修改。<br>2、当字段有数据并用要修改的新类型和原类型不兼容时，要间接新建字段来转移。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Oracle 数据库使用很久了，但是使用过程中出现的一些问题从来在也没有记录、每次出现同样的问题使用时又忘记了，又要搜索资料查询、浪费时间、so! 还是写个笔记记录下吧&lt;/p&gt;</summary>
    
    
    
    <category term="后端开发" scheme="http://next.skyheng.com/categories/%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="oracle" scheme="http://next.skyheng.com/categories/%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91/oracle/"/>
    
    
    <category term="oracle" scheme="http://next.skyheng.com/tags/oracle/"/>
    
  </entry>
  
  <entry>
    <title>有哪些好看的 Hexo 主题</title>
    <link href="http://next.skyheng.com/post/63199.html"/>
    <id>http://next.skyheng.com/post/63199.html</id>
    <published>2020-05-29T03:12:15.000Z</published>
    <updated>2025-11-30T14:41:25.914Z</updated>
    
    <content type="html"><![CDATA[<p>这个地方是写描述的地方</p><span id="more"></span><p><a href="https://www.zhihu.com/question/24422335/answers/created">有哪些好看的 <em>Hexo</em> <em>主题</em>? - 知乎</a></p><p>Hexo 好看的主题推荐 <a href="https://blog.csdn.net/zgd826237710/article/details/99671027">https://blog.csdn.net/zgd826237710/article/details/99671027</a></p><p>五款<strong>Hexo****主题</strong>推荐</p><p>1.Sakura 非常炫，缺点加载慢 <a href="https://github.com/honjun/hexo-theme-sakura">https://github.com/honjun/<strong>hexo</strong>-theme-sakura</a></p><p>2.Matery 预加载，强推 <a href="https://github.com/blinkfox/hexo-theme-matery">https://github.com/blinkfox/hexo-theme-matery</a></p><p>3.3-<strong>hexo</strong> 三段式，适合博文多的 <a href="https://github.com/yelog/hexo-theme-3-hexo">https://github.com/yelog/<strong>hexo</strong>-theme-3-<strong>hexo</strong></a></p><p>4.Butterfly 也是个好看的</p><p>5.Next 功能集成多，简洁</p><p>Hexo 好看的主题推荐 <a href="https://blog.csdn.net/zgd826237710/article/details/99671027">https://blog.csdn.net/zgd826237710/article/details/99671027</a></p><p><a href="https://blog.wangriyu.wang/2017/08-Hexo.html">https://blog.wangriyu.wang/2017/08-Hexo.html</a></p><p>butterfly</p><p>具体可以看我链接:</p><p><a href="https://xingjiahui.top/">https://xingjiahui.top</a></p><p><a href="https://blinkfox.github.io/">https://blinkfox.github.io/</a></p><p><a href="https://axh2018.gitee.io/categories/">https://axh2018.gitee.io/categories/</a></p><p>推荐网站：</p><ul><li>教程：<a href="https://easyhexo.com/">Easy Hexo</a>（非常详细，而且还有比较实用的进阶操作）</li><li>官网：<a href="https://hexo.io/">Hexo</a></li><li>百度：不解释</li><li>Google：不解释（打个广告需要。。。。的：<a href="https://www.17shou.vip/ssr/">链接</a>）</li></ul><p>推荐主题：</p><p>我推荐的主题 <a href="https://easyhexo.com/">Easy Hexo</a> 上都有，可以自己去看看。</p><h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><ul><li><a href=""></a></li></ul><h2 id="注"><a href="#注" class="headerlink" title="注"></a>注</h2><ul><li>本文转载自<a href="http://xxxxx/">http://xxxxx</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个地方是写描述的地方&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Spring Boot 2 实战：集成 MapStruct 类型转换神器</title>
    <link href="http://next.skyheng.com/post/53019.html"/>
    <id>http://next.skyheng.com/post/53019.html</id>
    <published>2020-05-27T01:36:03.000Z</published>
    <updated>2025-11-30T14:41:25.871Z</updated>
    
    <content type="html"><![CDATA[<p>MapStruct 官网：<a href="https://mapstruct.org/">https://mapstruct.org/</a></p><span id="more"></span><p><img data-src="https://image-static.segmentfault.com/359/176/3591769593-5da186e6ba15d" alt="img"></p><h2 id="1-痛点"><a href="#1-痛点" class="headerlink" title="1. 痛点"></a>1. 痛点</h2><p>一种框架的出现都要解决个痛点，我想下面这这种不方便的操作经常有人写吧。<br>假如<code>Car</code>类是数据库映射类:<br>​​</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.felord.mapstruct.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Car</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Felordcn</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 13:35 2019/10/12</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Car</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String make;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> numberOfSeats;</span><br><span class="line">    <span class="keyword">private</span> CarType type;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>CarType</code> 类：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.felord.mapstruct.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * CarType</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Felordcn</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 13:36 2019/10/12</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CarType</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String type;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>CarDTO</code>是DTO类:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.felord.mapstruct.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * CarDTO</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Felordcn</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 13:37 2019/10/12</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CarDTO</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String make;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> seatCount;</span><br><span class="line">    <span class="keyword">private</span> String type;</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure><p>我们从数据库查询<code>Car</code> 然后需要转换为<code>CarDTO</code>，通常我们会这么写一个方法进行转换：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> CarDTO <span class="title function_">carToCarDTO</span><span class="params">(Car car)</span> &#123;</span><br><span class="line">    <span class="type">CarDTO</span> <span class="variable">carDTO</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CarDTO</span>();</span><br><span class="line"></span><br><span class="line">    carDTO.setMake(car.getMake());</span><br><span class="line">    carDTO.setSeatCount(car.getNumberOfSeats());</span><br><span class="line">    carDTO.setType(car.getCarType().getType());</span><br><span class="line">    <span class="comment">// 有可能更长 </span></span><br><span class="line">    <span class="keyword">return</span> carDTO;</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure><p>这种写法非常繁琐无味，而且没有技术含量。甚至中间还牵涉了很多类型转换，嵌套之类的繁琐操作，而我们想要的只是建立它们之间的映射关系而已。有没有一种通用的映射工具来帮我们搞定这一切。当然有而且还不少。有人说apache的<code>BeanUtil.copyProperties</code>可以实现，但是性能差而且容易出异常，很多规范严禁使用这种途径。以下是对几种对象映射框架的对比，大多数情况下 <code>MapStruct</code> 性能最高。原理类似于<code>lombok</code> ，<code>MapStruct</code>都是在编译期进行实现，而且基于<code>Getter</code>、<code>Setter</code>,没有使用反射所以一般不存在运行时性能问题。</p><p><img data-src="https://image-static.segmentfault.com/530/930/530930600-5da186e704c49" alt="diff.png"></p><p>今天就搞一搞<strong>MapStruct</strong>, 并跟Spring Boot 2.x 集成以下。 无论是idea 还是eclipse 都建议安装 <strong>MapStruct Plugin</strong> 插件,当然不安装也是可以的。</p><h2 id="2-Spring-Boot-2-1-9-集成-MapStruct"><a href="#2-Spring-Boot-2-1-9-集成-MapStruct" class="headerlink" title="2. Spring Boot 2.1.9 集成 MapStruct"></a>2. Spring Boot 2.1.9 集成 MapStruct</h2><p>在 Spring Boot 的 <code>pom.xml</code> 下引入 <code>MapStruct</code> 的 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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.mapstruct<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>mapstruct<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;mapstruct.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.mapstruct<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>mapstruct-processor<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;mapstruct.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- other dependencies --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="3-使用MapStruct"><a href="#3-使用MapStruct" class="headerlink" title="3. 使用MapStruct"></a>3. 使用MapStruct</h2><p>我们把开始的痛点解决一下。看看 <strong>MapStruct</strong> 如何降低你的编程成本。</p><h3 id="3-1-编写转换源到目标的映射"><a href="#3-1-编写转换源到目标的映射" class="headerlink" title="3.1 编写转换源到目标的映射"></a>3.1 编写转换源到目标的映射</h3><p>编写<code>Car</code>到<code>CarDTO</code>的映射:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.felord.mapstruct.mapping;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.felord.mapstruct.entity.Car;</span><br><span class="line"><span class="keyword">import</span> cn.felord.mapstruct.entity.CarDTO;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.Mapper;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.Mapping;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.factory.Mappers;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * CarMapping</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Felordcn</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 14 :02 2019/10/12</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">CarMapping</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用来调用实例 实际开发中可使用注入Spring  不写</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">CarMapping</span> <span class="variable">CAR_MAPPING</span> <span class="operator">=</span> Mappers.getMapper(CarMapping.class);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *  源类型 目标类型 成员变量相同类型 相同变量名 不用写&#123;<span class="doctag">@link</span> org.mapstruct.Mapping&#125;来映射</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> car the car</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> the car dto</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Mapping(target = &quot;type&quot;, source = &quot;carType.type&quot;)</span></span><br><span class="line">    <span class="meta">@Mapping(target = &quot;seatCount&quot;, source = &quot;numberOfSeats&quot;)</span></span><br><span class="line">    CarDTO <span class="title function_">carToCarDTO</span><span class="params">(Car car)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-MapStruct映射方法讲解"><a href="#3-2-MapStruct映射方法讲解" class="headerlink" title="3.2 MapStruct映射方法讲解"></a>3.2 MapStruct映射方法讲解</h3><p>上面短短几行代码就可以了十分简单！解释一下操作步骤：</p><p>首先声明一个映射接口用<code>@org.mapstruct.Mapper</code> （不要跟mybatis注解混淆）标记，说明这是一个实体类型转换接口。这里我们声明了一个 <code>CAR_MAPPING</code> 来方便我们调用，<code>CarDTO toCarDTO(Car car)</code>是不是很熟悉， 像<code>mybatis</code>一样抽象出我们的转换方法。<code>@org.mapstruct.Mapping</code>注解用来声明成员属性的映射。该注解有两个重要的属性：</p><ul><li><code>source</code> 代表转换的源。这里就是<code>Car</code> 。</li><li><code>target</code> 代表转换的目标。这里是<code>CarDTO</code> 。</li></ul><p>这里以成员变量的参数名为依据，如果有嵌套比如 <code>Car</code> 里面有个 <code>CarType</code> 类型的成员变量 <code>carType</code>，其 <code>type</code> 属性 来映射 <code>CarDTO</code> 中的 <code>type</code> 字符串，我们使用 <code>type.type</code> 来获取属性值。如果有多层以此类推。<code>MapStruct</code> 最终调用的是 <code>setter</code> 和 <code>getter</code> 方法，而非反射。这也是其性能比较好的原因之一。<code>numberOfSeats</code> 映射到 <code>seatCount</code> 就比较好理解了。我们是不是忘记了一个属性 <code>make</code>，因为他们的位置且名称完全一致，所以可以省略。而且对于包装类是自动拆箱封箱操作的，并且是线程安全的。MapStruct不单单有这些功能，还有其他一些复杂的功能：</p><p>设置转换默认值和常量。当目标值是 <code>null</code> 时我们可以设置其默认值，注意这些都是基本类型以及对应都 <code>boxing</code> 类型，如下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@Mapping(target = &quot;stringProperty&quot;, source = &quot;stringProp&quot;, defaultValue = &quot;undefined&quot;)</span><br></pre></td></tr></table></figure><p>需要注意的是常量不能对源进行引用（不能指定 <code>source</code> 属性），下面是正确的操作:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@Mapping(target = &quot;stringConstant&quot;, constant = &quot;Constant Value&quot;)</span><br></pre></td></tr></table></figure><h3 id="3-2-Mapper-编译"><a href="#3-2-Mapper-编译" class="headerlink" title="3.2 Mapper 编译"></a>3.2 Mapper 编译</h3><p>当你的应用编译后。你会在编译后的目录比如 maven是 <code>target\generated-sources\annotations</code> 下的子目录发现生成了一个实现类 比如 我们上面的<code>CarMapping</code> 会生成<code>CarMappingImpl</code> 如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.felord.mapstruct.mapping;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> cn.felord.mapstruct.entity.Car;</span><br><span class="line"><span class="keyword">import</span> cn.felord.mapstruct.entity.CarDTO;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.Mapper;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.Mapping;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.factory.Mappers;</span><br><span class="line"><span class="keyword">import</span> javax.annotation.Generated;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Generated(</span></span><br><span class="line"><span class="meta">    value = &quot;org.mapstruct.ap.MappingProcessor&quot;,</span></span><br><span class="line"><span class="meta">    date = &quot;2019-10-12T15:05:36+0800&quot;,</span></span><br><span class="line"><span class="meta">    comments = &quot;version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_222 (Amazon.com Inc.)&quot;</span></span><br><span class="line"><span class="meta">)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CarMappingImpl</span> <span class="keyword">implements</span> <span class="title class_">CarMapping</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> CarDTO <span class="title function_">carToCarDTO</span><span class="params">(Car car)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> ( car == <span class="literal">null</span> ) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">CarDTO</span> <span class="variable">carDTO</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CarDTO</span>();</span><br><span class="line"></span><br><span class="line">        carDTO.setType( carCarTypeType( car ) );</span><br><span class="line">        carDTO.setSeatCount( car.getNumberOfSeats() );</span><br><span class="line">        carDTO.setMake( car.getMake() );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> carDTO;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String <span class="title function_">carCarTypeType</span><span class="params">(Car car)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> ( car == <span class="literal">null</span> ) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">CarType</span> <span class="variable">carType</span> <span class="operator">=</span> car.getCarType();</span><br><span class="line">        <span class="keyword">if</span> ( carType == <span class="literal">null</span> ) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">type</span> <span class="operator">=</span> carType.getType();</span><br><span class="line">        <span class="keyword">if</span> ( type == <span class="literal">null</span> ) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> type;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-MapStruct-进阶操作"><a href="#4-MapStruct-进阶操作" class="headerlink" title="4. MapStruct 进阶操作"></a>4. MapStruct 进阶操作</h2><p>下面介绍几种 <strong>MapStruct</strong> 的进阶操作：</p><h3 id="4-1-格式化操作"><a href="#4-1-格式化操作" class="headerlink" title="4.1 格式化操作"></a>4.1 格式化操作</h3><p>格式化也是我们经常使用的操作，比如数字格式化，日期格式化。<br>这是处理数字格式化的操作，遵循<code>java.text.DecimalFormat</code>的规范:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@Mapping(source = &quot;price&quot;, numberFormat = &quot;$#.00&quot;)</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@IterableMapping(dateFormat = &quot;dd.MM.yyyy&quot;)</span></span><br><span class="line">List&lt;String&gt; <span class="title function_">stringListToDateList</span><span class="params">(List&lt;Date&gt; dates)</span>;</span><br></pre></td></tr></table></figure><h3 id="4-2-使用-java-表达式"><a href="#4-2-使用-java-表达式" class="headerlink" title="4.2 使用 java 表达式"></a>4.2 使用 java 表达式</h3><p>下面演示如何使用<code>LocalDateTime</code> 作为当前的时间值注入 <code>addTime</code> 属性中。</p><p>首先在<code>@org.mapstruct.Mapper</code> 的 <code>imports</code> 属性中导入 <code>LocalDateTime</code>，该属性是数组意味着你可以根据需要导入更多的处理类：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@Mapper(imports = &#123;LocalDateTime.class&#125;)</span><br></pre></td></tr></table></figure><p>接下来只需要在对应的方法上添加注解<code>@org.mapstruct.Mapping</code> ，其属性<code>expression</code> 接收一个 <code>java()</code> 包括的表达式：</p><ul><li><p>无入参版本：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@Mapping(target = &quot;addTime&quot;, expression = &quot;java(LocalDateTime.now())&quot;)</span><br></pre></td></tr></table></figure></li><li><p>携带入参的版本, 我们将 <code>Car</code> 的出厂日期字符串<code>manufactureDateStr</code> 注入到 <code>CarDTO</code> 的 <code>LocalDateTime</code> 类型属性<code>addTime</code> 中去：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@Mapping(target = &quot;addTime&quot;, expression = &quot;java(LocalDateTime.parse(car.manufactureDateStr))&quot;)</span><br><span class="line">CarDTO carToCarDTO(Car car);</span><br></pre></td></tr></table></figure></li></ul><h3 id="4-3-MapStruct-转换-Mapper-注入Spring-IoC-容器"><a href="#4-3-MapStruct-转换-Mapper-注入Spring-IoC-容器" class="headerlink" title="4.3 MapStruct 转换 Mapper 注入Spring IoC 容器"></a>4.3 MapStruct 转换 Mapper 注入Spring IoC 容器</h3><p>如果使用要把Mapper 注入Spring IoC 容器我们只需要这么声明，不用再构建一个单例，就可以像其他 spring bean一样对CarMapping 进行引用了：</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></pre></td><td class="code"><pre><span class="line"> <span class="keyword">package</span> cn.felord.mapstruct.mapping;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">import</span> cn.felord.mapstruct.entity.Car;</span><br><span class="line"> <span class="keyword">import</span> cn.felord.mapstruct.entity.CarDTO;</span><br><span class="line"> <span class="keyword">import</span> org.mapstruct.Mapper;</span><br><span class="line"> <span class="keyword">import</span> org.mapstruct.Mapping;</span><br><span class="line"> <span class="keyword">import</span> org.mapstruct.factory.Mappers;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * CarMapping 注入spring 写法</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Felordcn</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 14 :02 2019/10/12</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Mapper(componentModel = &quot;spring&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">CarMapping</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用来调用实例 实际开发中可使用注入Spring  不写</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">  <span class="comment">// CarMapping CAR_MAPPING = Mappers.getMapper(CarMapping.class);</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 源类型 目标类型 成员变量相同类型 相同变量名 不用写&#123;<span class="doctag">@link</span> Mapping&#125;来映射</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> car the car</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> the car dto</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Mapping(target = &quot;type&quot;, source = &quot;carType.type&quot;)</span></span><br><span class="line">    <span class="meta">@Mapping(target = &quot;seatCount&quot;, source = &quot;numberOfSeats&quot;)</span></span><br><span class="line">    CarDTO <span class="title function_">carToCarDTO</span><span class="params">(Car car)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-总结"><a href="#5-总结" class="headerlink" title="5.总结"></a>5.总结</h2><p>其实MapStruct 还有很多的功能。但是从可读性来说，我建议使用以上几种容易理解的功能即可。如果你感兴趣可以去mapstruct.org进一步学习。配合lombok和我介绍的jsr303，让你更加专注于业务，而且代码更加清晰。</p><h2 id="6-资料"><a href="#6-资料" class="headerlink" title="6.资料"></a>6.资料</h2><ul><li><a href="http://nullpointer.pw/mapstruct%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5.html">mapstruct最佳实践</a></li><li><a href="https://www.cnblogs.com/vcmq/archive/2020/03/21/12542336.html">mapstruct最佳实践- 博客园</a></li><li><a href="https://blog.csdn.net/zhige_me/article/details/80699784">推荐一个Java实体映射工具MapStruct</a></li><li><a href="https://segmentfault.com/a/1190000020663215">Spring Boot 2实战：集成MapStruct类型转换神器</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;MapStruct 官网：&lt;a href=&quot;https://mapstruct.org/&quot;&gt;https://mapstruct.org/&lt;/a&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="java" scheme="http://next.skyheng.com/categories/java/"/>
    
    <category term="springBoot" scheme="http://next.skyheng.com/categories/java/springBoot/"/>
    
    
    <category term="java" scheme="http://next.skyheng.com/tags/java/"/>
    
    <category term="springBoot" scheme="http://next.skyheng.com/tags/springBoot/"/>
    
    <category term="MapStruct" scheme="http://next.skyheng.com/tags/MapStruct/"/>
    
  </entry>
  
  <entry>
    <title>极致简洁的markdown编辑器Typora的使用记录与修改</title>
    <link href="http://next.skyheng.com/post/23202.html"/>
    <id>http://next.skyheng.com/post/23202.html</id>
    <published>2020-05-20T07:00:52.000Z</published>
    <updated>2025-11-30T14:41:25.910Z</updated>
    
    <content type="html"><![CDATA[<p>​有一种爱情是一触即发。看到Typora的第一眼，我就爱上了它。它没有专业软件那么复杂而难以上手的功能，却也没有为了简洁而妥协到难以使用，它的每一寸肌肤都恰到好处，与它相处的每一刻都十分愉悦。</p><span id="more"></span><p><img data-src="http://qn.blog.skyheng.com/img/typora-icon.png" alt="typora"></p><img data-src="http://qn.blog.skyheng.com/img/typora-icon.png" style="zoom:70%;" /><h3 id="Typora安装"><a href="#Typora安装" class="headerlink" title="Typora安装"></a>Typora安装</h3><ul><li>在<a href="https://www.baidu.com/link?url=ENQ0grDqs9eMNlp9elDZ5Nn_z2q8_ixOp1UGglXPcMe&wd=&eqid=8fe1c4910000ad9f000000065c7f6ff3">typora官网</a>下载相对应电脑系统版本的软件，比如windows，Mac。</li><li>正常安装即可</li></ul><h3 id="Typora的设置"><a href="#Typora的设置" class="headerlink" title="Typora的设置"></a>Typora的设置</h3><ol><li>找到：文件–偏好设置<ol><li>设置字体大小：可以使用自定义</li><li>图片插入：复制到${filename}.asset文件夹；打钩优先使用相对路径(默认从C盘的某个路径，当移动md文档时，图片不好粘贴出来，这个最好设置一下)！！！</li><li>设置插入代码时显示行号：代码块–打钩显示行号</li><li>保存&amp;恢复：打钩自动保存（防止电脑死机，断电等）！！！</li><li>关闭自动检查更新！！！</li></ol></li><li>设置视图<ol><li>视图–大纲视图！！！</li></ol></li><li>设置首行缩进：或者按tab键就可以<ol><li>编辑–空格与换行–首行缩进</li></ol></li></ol><p>备注：！！！为我自己设置的内容</p><h3 id="Markdown语法"><a href="#Markdown语法" class="headerlink" title="Markdown语法"></a>Markdown语法</h3><blockquote><p>Typora软件遵循markdown语法的编辑语法</p></blockquote><p>Markdown语法记忆起来较简单，之所以要学一个语法来用一款编辑文本的软件，那是因为Markdown编辑方便，简单上手，编辑后的内容看起来不会像普通txt文本那样丑陋~，同时插入代码等表格也方便和耐看。</p><h3 id="Typora写作内容保存到简书"><a href="#Typora写作内容保存到简书" class="headerlink" title="Typora写作内容保存到简书"></a>Typora写作内容保存到简书</h3><blockquote><p>注册一个简书，进入写文章，左下角点击设置，设置编辑器为markdown编辑器</p></blockquote><p>复制Typora的内容到简书即可！！</p><h3 id="Typora的其他技巧和注意事项"><a href="#Typora的其他技巧和注意事项" class="headerlink" title="Typora的其他技巧和注意事项"></a>Typora的其他技巧和注意事项</h3><ul><li>插入目录：使用**[toc]或[TOC]<strong>在Typora里就会自动识别为目录；或者点击</strong>段落–内容目录**，也可以插入目录；目录即为你用#号生成的标题的汇总</li><li>md文档设置为txt文本：点击<strong>另存为</strong>选择<strong>txt</strong>或者把.md后缀改为.md.txt，.md.ttx是来提醒自己这是一个md的txt文档</li><li>通常<strong>Typora的自动md语法还是比较方便的</strong>，建议在本地用typora写完，然后复制到简书来发布。比如typora插入代码的时候，不需要输入结束的三个反引号，插入表格的时候可以用鼠标点击左上角来更改插入几列几行，插入有序&#x2F;无序列表时按enter键自动识别，tab键自动下一级或快捷键加粗等等；所以<strong>建议大家记录学习笔记的时候用typora记录</strong></li><li>简书会自动保存，typora默认不自动保存，这个需要设置一下！！！</li><li><strong>Typora的图片是默认存在本地文件夹</strong>，因此复制内容到简书的时候，图片需要额外插入，这点有点麻烦，有写公众号推文的人都有这个经历，插图片能让你每次怀疑人生！</li><li>Typora可以在<strong>文件–导出</strong>，导出成其他格式的文本，这点也很方便，比如PDF</li><li>如果设置过“图片插入”，md文档也插入了图片，需要给别人发送该md文档的时候，需要一并打包<strong>该文档+同目录下的图片文件夹</strong>然后发送出去。</li><li>快速放大：windows电脑是ctrl+shift+加号</li><li>快速缩小：windows电脑是ctrl+shift+减号</li><li>快速栏找到“主题”：选择Night</li><li>最重要的是，各大博客和论坛都可以识别md语法</li><li>ctrl+3(或1&#x2F;2&#x2F;4&#x2F;5)快速调节3级标题</li></ul><h3 id="个人修改"><a href="#个人修改" class="headerlink" title="个人修改"></a>个人修改</h3><p>修改主题编辑区域宽度</p><p>在偏好设置&gt;外观&gt;主题 打开主题文件夹、找到对应的主题css、这里已vue.css 为例、编辑器区域宽度是由<code>#write</code> 控制的</p><p>原css代码片段</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#write</span> &#123;</span><br><span class="line">    <span class="attribute">max-width</span>: <span class="number">860px</span>;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">0</span> auto;</span><br><span class="line">    <span class="attribute">padding</span>: <span class="number">20px</span> <span class="number">30px</span> <span class="number">100px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>修改后的css代码片段</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#write</span> &#123;</span><br><span class="line">    <span class="attribute">max-width</span>: <span class="number">98%</span>;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">0</span> auto;</span><br><span class="line">    <span class="attribute">padding</span>: <span class="number">20px</span> <span class="number">30px</span> <span class="number">100px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>修改图片展示</p><p>原本大多主题的图片展示都是居中的，看起来非常的不舒服、我把图片调成了靠右展示</p><p>添加css</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">p</span>&gt;<span class="selector-class">.md-image</span><span class="selector-pseudo">:only-child</span><span class="selector-pseudo">:not</span>(<span class="selector-class">.md-img-error</span>) <span class="selector-tag">img</span>,<span class="selector-tag">p</span>&gt;<span class="selector-tag">img</span><span class="selector-pseudo">:only-child</span> &#123;</span><br><span class="line">    <span class="attribute">margin</span>: inherit;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>修改源代码模式编辑区域</p><p>打开Typora所在的安装目录、例<code>C:\Software\Typora\resources\app\style</code></p><p>base-control.css</p><p>原css代码片段</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.CodeMirror-lines</span> &#123;</span><br><span class="line"><span class="attribute">padding-top</span>: <span class="number">30px</span>;</span><br><span class="line"><span class="attribute">padding-bottom</span>: <span class="number">60px</span>;</span><br><span class="line"><span class="attribute">padding-left</span>: <span class="number">60px</span>;</span><br><span class="line"><span class="attribute">padding-right</span>: <span class="number">30px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>修改后的css代码片段</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.CodeMirror-lines</span> &#123;</span><br><span class="line"><span class="attribute">padding-top</span>: <span class="number">30px</span>;</span><br><span class="line"><span class="attribute">padding-bottom</span>: <span class="number">60px</span>;</span><br><span class="line"><span class="attribute">padding-left</span>: <span class="number">60px</span>;</span><br><span class="line"><span class="attribute">padding-right</span>: <span class="number">30px</span>;</span><br><span class="line"><span class="attribute">max-width</span>: <span class="number">98%</span>;</span><br><span class="line"><span class="attribute">margin</span>: <span class="number">0</span> auto;</span><br><span class="line"><span class="attribute">border</span>: solid <span class="number">1px</span> <span class="number">#5cb85c</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**压缩后为*/</span></span><br><span class="line">// <span class="attribute">max-width</span>: <span class="number">98%</span>;<span class="attribute">margin</span>: <span class="number">0</span> auto;<span class="attribute">border</span>: solid <span class="number">1px</span> <span class="number">#5cb85c</span>;</span><br></pre></td></tr></table></figure><h3 id="优秀文章"><a href="#优秀文章" class="headerlink" title="优秀文章"></a>优秀文章</h3><ul><li>Typora+PicGo，最好用的Markdown+最好用的图床工具 <a href="https://blog.csdn.net/bruce_6/article/details/104821531">https://blog.csdn.net/bruce_6/article/details/104821531</a></li><li>Typora[MarkDown编辑器]+(PicGo+Github+JsDelivr）<a href="https://blog.csdn.net/c1ata/article/details/104744457">https://blog.csdn.net/c1ata/article/details/104744457</a></li><li><a href="https://www.jianshu.com/p/5634b207d516">美化Typora的中文字体，让编辑简书成为一种享受 </a></li><li><a href="https://www.cnblogs.com/superdrew/p/12821051.html">Typora添加主题</a></li></ul><h3 id="图片测试"><a href="#图片测试" class="headerlink" title="图片测试"></a>图片测试</h3><img data-src="http://qn.blog.skyheng.com/img/typora-icon.png" style="zoom:50%;" /><ul><li><img data-src="http://qn.blog.skyheng.com/img/image-20200516112139894.png" style="zoom:65%;" /></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;​	有一种爱情是一触即发。看到Typora的第一眼，我就爱上了它。它没有专业软件那么复杂而难以上手的功能，却也没有为了简洁而妥协到难以使用，它的每一寸肌肤都恰到好处，与它相处的每一刻都十分愉悦。&lt;/p&gt;</summary>
    
    
    
    <category term="software" scheme="http://next.skyheng.com/categories/software/"/>
    
    <category term="Typora" scheme="http://next.skyheng.com/categories/software/Typora/"/>
    
    
    <category term="markdown" scheme="http://next.skyheng.com/tags/markdown/"/>
    
    <category term="Typora" scheme="http://next.skyheng.com/tags/Typora/"/>
    
  </entry>
  
  <entry>
    <title>打造个人专属Sublime Text 3</title>
    <link href="http://next.skyheng.com/post/31282.html"/>
    <id>http://next.skyheng.com/post/31282.html</id>
    <published>2019-11-26T09:39:41.000Z</published>
    <updated>2025-11-30T14:41:25.906Z</updated>
    
    <content type="html"><![CDATA[<p>目前使用的版本是sublime text3。选择sublime的理由<br>1、sublime Text是一个跨平台代码编辑器，可以在linux&#x2F;windows&#x2F;OS X下使用；<br>2、sublime Text可以根据用户的需求添加插件进行扩展（使用javascript，html等有相应的插件，写代码方便快捷）<br>3、sublime Text的界面简单易操作（个人很喜欢sublime根据代码不同而显示不同颜色的功能，用户也可以根据自己的喜好配置颜色）</p><span id="more"></span><p><img data-src="/images/2019/11/26/5ae16020-104c-11ea-9fda-2da015a5a954.png" alt="sublime2.png"></p><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><h3 id="1-下载与破解"><a href="#1-下载与破解" class="headerlink" title="1. 下载与破解"></a>1. 下载与破解</h3><p>当前可用的破解码如下：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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">—– BEGIN LICENSE —–</span><br><span class="line">Andrew Weber</span><br><span class="line">Single User License</span><br><span class="line">EA7E-855605</span><br><span class="line">813A03DD 5E4AD9E6 6C0EEB94 BC99798F</span><br><span class="line">942194A6 02396E98 E62C9979 4BB979FE</span><br><span class="line">91424C9D A45400BF F6747D88 2FB88078</span><br><span class="line">90F5CC94 1CDC92DC 8457107A F151657B</span><br><span class="line">1D22E383 A997F016 42397640 33F41CFC</span><br><span class="line">E1D0AE85 A0BBD039 0E9C8D55 E1B89D5D</span><br><span class="line">5CDB7036 E56DE1C0 EFCC0840 650CD3A6</span><br><span class="line">B98FC99C 8FAC73EE D2B95564 DF450523</span><br><span class="line">—— END LICENSE ——</span><br></pre></td></tr></table></figure><p>分享Sublime Text 3序列号一枚：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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">—– BEGIN LICENSE —–</span><br><span class="line">Andrew Weber</span><br><span class="line">Single User License</span><br><span class="line">EA7E-855605</span><br><span class="line">813A03DD 5E4AD9E6 6C0EEB94 BC99798F</span><br><span class="line">942194A6 02396E98 E62C9979 4BB979FE</span><br><span class="line">91424C9D A45400BF F6747D88 2FB88078</span><br><span class="line">90F5CC94 1CDC92DC 8457107A F151657B</span><br><span class="line">1D22E383 A997F016 42397640 33F41CFC</span><br><span class="line">E1D0AE85 A0BBD039 0E9C8D55 E1B89D5D</span><br><span class="line">5CDB7036 E56DE1C0 EFCC0840 650CD3A6</span><br><span class="line">B98FC99C 8FAC73EE D2B95564 DF450523</span><br><span class="line">—— END LICENSE ——</span><br></pre></td></tr></table></figure><p>参见：</p><ul><li><a href="http://www.xiumu.org/note/sublime-text-3.shtml">Sublime Text 3 破解版 + 注册机 + 汉化包 + 教程</a></li><li><a href="http://www.waitsun.com/sublime-text-3-for-mac.html">Sublime Text 3 for Mac 3075 破解版 – Mac上强大的代码编辑神器</a></li><li><a href="https://www.shuax.com/archives/SublimeText3Crack.html">Sublime Text 3破解补丁</a></li></ul><h3 id="2-Sublime-Text-2与Sublime-Text-3区别"><a href="#2-Sublime-Text-2与Sublime-Text-3区别" class="headerlink" title="2. Sublime Text 2与Sublime Text 3区别"></a>2. Sublime Text 2与Sublime Text 3区别</h3><p>简单的说：</p><ul><li>ST3支持在项目目录里面寻找变量提供了</li><li>对标签页更好地支持（更多的命令和快捷键）</li><li>加快了程序运行的速度</li><li>更新了API，使用Python3.3</li></ul><p>参见：</p><ul><li><a href="https://www.zhihu.com/question/25078353">Sublime Text3与Sublime Text 2的区别在哪里？</a></li><li><a href="http://tutorial.jingwentian.com/Sublime-Text-3-Documentation/porting_guide.html">Sublime Text 3 文档之迁移指南</a></li></ul><h2 id="二、配置"><a href="#二、配置" class="headerlink" title="二、配置"></a>二、配置</h2><h3 id="1-我的配置"><a href="#1-我的配置" class="headerlink" title="1. 我的配置"></a>1. 我的配置</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"><span class="attr">&quot;ignored_packages&quot;</span><span class="punctuation">:</span></span><br><span class="line"><span class="punctuation">[</span></span><br><span class="line"><span class="string">&quot;Vintage&quot;</span></span><br><span class="line"><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 字体</span></span><br><span class="line"><span class="attr">&quot;font_size&quot;</span><span class="punctuation">:</span> <span class="number">12</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 高亮当前行</span></span><br><span class="line"><span class="attr">&quot;highlight_line&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 新标签页打开文件</span></span><br><span class="line"><span class="attr">&quot;preview_on_click&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//滚动能否超过结尾</span></span><br><span class="line"><span class="attr">&quot;scroll_past_end&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// TAB缩进宽度</span></span><br><span class="line"><span class="attr">&quot;tab_size&quot;</span><span class="punctuation">:</span> <span class="number">4</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 自动转换TAB为空格</span></span><br><span class="line"><span class="attr">&quot;translate_tabs_to_spaces&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 皮肤</span></span><br><span class="line"><span class="attr">&quot;theme&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Soda Dark 3.sublime-theme&quot;</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭自动更新</span></span><br><span class="line"><span class="attr">&quot;update_check&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 自动换行</span></span><br><span class="line"><span class="attr">&quot;word_wrap&quot;</span><span class="punctuation">:</span> <span class="string">&quot;true&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h3 id="2-关闭自动更新"><a href="#2-关闭自动更新" class="headerlink" title="2. 关闭自动更新"></a>2. 关闭自动更新</h3><p>SublimeText的升级挺快的，每次升级完之后都要重新破解一次主文件，不用重新注册，如果嫌更新太麻烦可以在用户配置中加入如下配置禁用自动更新：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;update_check&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br></pre></td></tr></table></figure><h3 id="3-soda主题"><a href="#3-soda主题" class="headerlink" title="3. soda主题"></a>3. soda主题</h3><p>参见：<a href="https://github.com/buymeasoda/soda-theme/">https://github.com/buymeasoda/soda-theme/</a></p><p>通过package controller安装Theme - Soda。</p><h3 id="4-记住打开的文件"><a href="#4-记住打开的文件" class="headerlink" title="4. 记住打开的文件"></a>4. 记住打开的文件</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;remember_open_files&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br></pre></td></tr></table></figure><!-- more --><h3 id="5-Sublime-Text-2-使用-Eclipse-快捷键"><a href="#5-Sublime-Text-2-使用-Eclipse-快捷键" class="headerlink" title="5. Sublime Text 2 使用 Eclipse 快捷键"></a>5. Sublime Text 2 使用 Eclipse 快捷键</h3><p><a href="https://gist.github.com/ufologist/5590481#file-package-control-sublime-settings">Sublime Text User Preferences – Eclipse shortcuts for Sublime Text</a><br><a href="http://www.douban.com/note/276794943/">打造属于自己的前端开发神器 – 给Sublime Text加上Eclipse的光环</a></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">[</span></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 常用快捷键(Sublime默认)</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></span><br><span class="line"><span class="comment">     * &#123; &quot;keys&quot;: [&quot;super+left&quot;], &quot;command&quot;: &quot;move&quot;, &quot;args&quot;: &#123;&quot;by&quot;: &quot;words&quot;, &quot;forward&quot;: false&#125; &#125;,</span></span><br><span class="line"><span class="comment">     * 按住shift来选文字时, 一个个单词的选而不是一个个字母</span></span><br><span class="line"><span class="comment">     * &#123; &quot;keys&quot;: [&quot;super+shift+left&quot;], &quot;command&quot;: &quot;move&quot;, &quot;args&quot;: &#123;&quot;by&quot;: &quot;words&quot;, &quot;forward&quot;: false, &quot;extend&quot;: true&#125; &#125;,</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">     * &#123; &quot;keys&quot;: [&quot;alt+left&quot;], &quot;command&quot;: &quot;move&quot;, &quot;args&quot;: &#123;&quot;by&quot;: &quot;subwords&quot;, &quot;forward&quot;: false&#125; &#125;,</span></span><br><span class="line"><span class="comment">     * &#123; &quot;keys&quot;: [&quot;alt+shift+right&quot;], &quot;command&quot;: &quot;move&quot;, &quot;args&quot;: &#123;&quot;by&quot;: &quot;subword_ends&quot;, &quot;forward&quot;: true, &quot;extend&quot;: true&#125; &#125;,</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">     * &#123; &quot;keys&quot;: [&quot;super+]&quot;], &quot;command&quot;: &quot;indent&quot; &#125;,</span></span><br><span class="line"><span class="comment">     * &#123; &quot;keys&quot;: [&quot;super+[&quot;], &quot;command&quot;: &quot;unindent&quot; &#125;,</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">     * &#123; &quot;keys&quot;: [&quot;super+backspace&quot;], &quot;command&quot;: &quot;delete_word&quot;, &quot;args&quot;: &#123; &quot;forward&quot;: false &#125; &#125;,</span></span><br><span class="line"><span class="comment">     * &#123; &quot;keys&quot;: [&quot;super+delete&quot;], &quot;command&quot;: &quot;delete_word&quot;, &quot;args&quot;: &#123; &quot;forward&quot;: true &#125; &#125;,</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * 行排序(例如选中几个JSON字段, 让这些字段名按字母顺序排序)</span></span><br><span class="line"><span class="comment">     * &#123; &quot;keys&quot;: [&quot;f9&quot;], &quot;command&quot;: &quot;sort_lines&quot;, &quot;args&quot;: &#123;&quot;case_sensitive&quot;: false&#125; &#125;,</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></span><br><span class="line"><span class="comment">     * Using Sublime Text as your IDE</span></span><br><span class="line"><span class="comment">     * http://www.chromium.org/developers/sublime-text</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * Web Development With Sublime Text 2</span></span><br><span class="line"><span class="comment">     * http://www.paulund.co.uk/web-development-with-sublime-text-2</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// editor配置</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+v&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;paste_and_indent&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+shift+v&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;paste&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 适配eclipse快捷键</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">     * Eclipse shortcuts for Sublime Text 2</span></span><br><span class="line"><span class="comment">     * http://icoloma.blogspot.com/2011/10/eclipse-shortcuts-for-sublime-text-2.html</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;alt+/&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;auto_complete&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+i&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;reindent&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 当前行和下面一行交互位置</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;alt+up&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;swap_line_up&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;alt+down&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;swap_line_down&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 复制当前行到上一行</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+alt+up&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;duplicate_line&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 复制当前行到下一行</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+alt+down&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;duplicate_line&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 删除整行</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+d&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;run_macro_file&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;file&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Packages/Default/Delete Line.sublime-macro&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 光标移动到指定行</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+l&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_overlay&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;overlay&quot;</span><span class="punctuation">:</span> <span class="string">&quot;goto&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;text&quot;</span><span class="punctuation">:</span> <span class="string">&quot;:&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 快速定位到选中的文字</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+k&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;find_under_expand_skip&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// &#123; &quot;keys&quot;: [&quot;super+shift+x&quot;], &quot;command&quot;: &quot;swap_case&quot; &#125;,</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+shift+x&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;upper_case&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+shift+y&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;lower_case&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置, 不一定是最后)</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;shift+enter&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;run_macro_file&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;file&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Packages/Default/Add Line.sublime-macro&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 定位到对于的匹配符(譬如&#123;&#125;)(从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+shift+p&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;move_to&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;to&quot;</span><span class="punctuation">:</span> <span class="string">&quot;brackets&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 这个命令默认使用的是super+shift+p</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+p&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_overlay&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;overlay&quot;</span><span class="punctuation">:</span> <span class="string">&quot;command_palette&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// outline</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+o&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_overlay&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;overlay&quot;</span><span class="punctuation">:</span> <span class="string">&quot;goto&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;text&quot;</span><span class="punctuation">:</span> <span class="string">&quot;@&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 当前文件中的关键字(方便快速查找内容)</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+alt+o&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_overlay&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;overlay&quot;</span><span class="punctuation">:</span> <span class="string">&quot;goto&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;text&quot;</span><span class="punctuation">:</span> <span class="string">&quot;#&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// open resource</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+shift+r&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_overlay&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;overlay&quot;</span><span class="punctuation">:</span> <span class="string">&quot;goto&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;show_files&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 文件内查找/替换</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+f&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_panel&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;panel&quot;</span><span class="punctuation">:</span> <span class="string">&quot;replace&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="comment">// 全局查找/替换, 在查询结果中双击跳转到匹配位置</span></span><br><span class="line">    <span class="punctuation">&#123;</span><span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+h&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;show_panel&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;panel&quot;</span><span class="punctuation">:</span> <span class="string">&quot;find_in_files&quot;</span><span class="punctuation">&#125;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// plugin配置</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;alt+a&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;alignment&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span><span class="attr">&quot;keys&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;super+shift+f&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;js_format&quot;</span><span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">]</span></span><br></pre></td></tr></table></figure><h2 id="三、插件"><a href="#三、插件" class="headerlink" title="三、插件"></a>三、插件</h2><h3 id="1-Package-Control"><a href="#1-Package-Control" class="headerlink" title="1. Package Control"></a>1. Package Control</h3><p>最简单的方式是通过 ctrl+`快捷键打开控制台，粘贴以下代码到控制台执行。<br>参见：<a href="https://packagecontrol.io/installation#st3">Package Control INSTALLATION</a></p><h4 id="Sublime-Text-3"><a href="#Sublime-Text-3" class="headerlink" title="Sublime Text 3"></a>Sublime Text 3</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> urllib.request,os,hashlib; h = <span class="string">&#x27;2915d1851351e5ee549c20394736b442&#x27;</span> + <span class="string">&#x27;8bc59f460fa1548d1514676163dafc88&#x27;</span>; pf = <span class="string">&#x27;Package Control.sublime-package&#x27;</span>; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( <span class="string">&#x27;http://packagecontrol.io/&#x27;</span> + pf.replace(<span class="string">&#x27; &#x27;</span>, <span class="string">&#x27;%20&#x27;</span>)).read(); dh = hashlib.sha256(by).hexdigest(); <span class="built_in">print</span>(<span class="string">&#x27;Error validating download (got %s instead of %s), please try manual install&#x27;</span> % (dh, h)) <span class="keyword">if</span> dh != h <span class="keyword">else</span> <span class="built_in">open</span>(os.path.join( ipp, pf), <span class="string">&#x27;wb&#x27;</span> ).write(by)</span><br></pre></td></tr></table></figure><h4 id="Sublime-Text-2"><a href="#Sublime-Text-2" class="headerlink" title="Sublime Text 2"></a>Sublime Text 2</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> urllib2,os,hashlib; h = <span class="string">&#x27;2915d1851351e5ee549c20394736b442&#x27;</span> + <span class="string">&#x27;8bc59f460fa1548d1514676163dafc88&#x27;</span>; pf = <span class="string">&#x27;Package Control.sublime-package&#x27;</span>; ipp = sublime.installed_packages_path(); os.makedirs( ipp ) <span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(ipp) <span class="keyword">else</span> <span class="literal">None</span>; urllib2.install_opener( urllib2.build_opener( urllib2.ProxyHandler()) ); by = urllib2.urlopen( <span class="string">&#x27;http://packagecontrol.io/&#x27;</span> + pf.replace(<span class="string">&#x27; &#x27;</span>, <span class="string">&#x27;%20&#x27;</span>)).read(); dh = hashlib.sha256(by).hexdigest(); <span class="built_in">open</span>( os.path.join( ipp, pf), <span class="string">&#x27;wb&#x27;</span> ).write(by) <span class="keyword">if</span> dh == h <span class="keyword">else</span> <span class="literal">None</span>; <span class="built_in">print</span>(<span class="string">&#x27;Error validating download (got %s instead of %s), please try manual install&#x27;</span> % (dh, h) <span class="keyword">if</span> dh != h <span class="keyword">else</span> <span class="string">&#x27;Please restart Sublime Text to finish installation&#x27;</span>)</span><br></pre></td></tr></table></figure><h3 id="2-实用插件"><a href="#2-实用插件" class="headerlink" title="2. 实用插件"></a>2. 实用插件</h3><ul><li>SideBarEnhancements 左侧菜单栏增强</li><li>ConvertToUTF8</li><li>AutoFileName 自动补全文件(目录)名</li><li>BracketHighlighter 突出显示括号&#x2F;引号</li><li>ColorHighlighter背景显示16进制颜色</li><li>DocBlockr 生成注释模板</li><li>Sublime CodeIntel – 智能代码提示</li><li>FreeMarker:Freemarker模板语言辅助</li><li>SublimeCodeIntel 代码提示</li><li>JSHint、JsFormart、jQuery</li><li>Color Highlighter</li><li>Indent XML</li><li>sublimeLinter</li><li>pretty json</li></ul><h3 id="我的插件"><a href="#我的插件" class="headerlink" title="我的插件"></a>我的插件</h3><p><img data-src="/images/2019/11/26/20191213113045.png" alt="我的插件"></p><p>参见：</p><ul><li><a href="http://blog.csdn.net/xby1993/article/details/23995667">sublime Text3配置及快捷键、插件推荐总结</a></li><li><a href="http://blog.useasp.net/archive/2013/06/14/sublime-text-2-all-default-Shortcuts-table-on-windows-translated-with-chinese.aspx">SublimeText2 快捷键一览表</a></li><li><a href="http://blog.jdk5.com/zh/sublime-text-3-license-key/">sublime text 3 注册码 破解码 license key</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;目前使用的版本是sublime text3。选择sublime的理由&lt;br&gt;1、sublime Text是一个跨平台代码编辑器，可以在linux&amp;#x2F;windows&amp;#x2F;OS X下使用；&lt;br&gt;2、sublime Text可以根据用户的需求添加插件进行扩展（使用javascript，html等有相应的插件，写代码方便快捷）&lt;br&gt;3、sublime Text的界面简单易操作（个人很喜欢sublime根据代码不同而显示不同颜色的功能，用户也可以根据自己的喜好配置颜色）&lt;/p&gt;</summary>
    
    
    
    <category term="software" scheme="http://next.skyheng.com/categories/software/"/>
    
    <category term="sublime" scheme="http://next.skyheng.com/categories/software/sublime/"/>
    
    
    <category term="sublime" scheme="http://next.skyheng.com/tags/sublime/"/>
    
  </entry>
  
  <entry>
    <title>office 2016选择性安装</title>
    <link href="http://next.skyheng.com/post/11314.html"/>
    <id>http://next.skyheng.com/post/11314.html</id>
    <published>2019-06-22T15:01:51.000Z</published>
    <updated>2025-11-30T14:41:25.906Z</updated>
    
    <content type="html"><![CDATA[<p>office2016在安装的时候并不像之前的版本有选择性的安装，安装器会安装一个office全家桶。那么如何自主选择安装自己需要的工具呢？</p><span id="more"></span><h2 id="方法一"><a href="#方法一" class="headerlink" title="方法一"></a>方法一</h2><h3 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h3><ol><li><p>下载Office2016部署工具，点此下载。</p></li><li><p>双击打开工具，该工具会释放两个我们需要的文件（setup.exe和configuration.xml）<br><img data-src="/images/2019/06/22/34fe72a0-ce5a-11e9-9ac2-3b88b69a7f58.png" alt="image.png"></p></li><li><p>用虚拟光驱加载你下载的Office2016 ISO镜像。</p></li><li><p>用记事本打开第2步解压得到的configuration文件，将其中的内容改为如下所示的样子：</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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">Configuration</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">Add</span> <span class="attr">SourcePath</span>=<span class="string">&quot;G:\&quot;</span> <span class="attr">OfficeClientEdition</span>=<span class="string">&quot;64&quot;</span> &gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">Product</span> <span class="attr">ID</span>=<span class="string">&quot;ProPlusRetail&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">Language</span> <span class="attr">ID</span>=<span class="string">&quot;zh-CN&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;Access&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;Groove&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;InfoPath&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;Lync&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;OneNote&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;Outlook&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;Publisher&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ExcludeApp</span> <span class="attr">ID</span>=<span class="string">&quot;SharePointDesigner&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">Product</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">Add</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">Configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ol><p><code>OfficeClientEdition</code>：表示架构，如果你想安装32位则改为32<br><code>SourcePath</code>：表示Office2016 ISO镜像加载位置（一般是G盘）</p><p><img data-src="/images/2019/06/22/4c4687e0-ce5a-11e9-9ac2-3b88b69a7f58.png" alt="image.png"></p><p><code>Language</code>：表示语言，zh-CN表示中文，如果你安装的是英文，则为en-us<br><code>ExcludeApp</code>：表示不被安装的组件，你可以看到这里面不包括Word、PowerPoint和Excel，我们的目的就是只安装这三个组件。你可以根据自己的需要删除或增加ExcludeApp。</p><ol start="5"><li>以管理员身份CMD，运行下面的命令即可：</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># cd到setup.exe文件夹下</span><br><span class="line">setup.exe /configure configuration.xml</span><br></pre></td></tr></table></figure><p><img data-src="/images/2019/06/22/55f244f0-ce5a-11e9-9ac2-3b88b69a7f58.png" alt="image.png"></p><p>方法参考：<a href="https://docs.microsoft.com/zh-cn/deployoffice/configuration-options-for-the-office-2016-deployment-tool#BKMK_ExcludeAppElement">Office 部署工具的配置选项</a></p><h2 id="方法二"><a href="#方法二" class="headerlink" title="方法二"></a>方法二</h2><h3 id="步骤-1"><a href="#步骤-1" class="headerlink" title="步骤"></a>步骤</h3><p><a href="https://www.52pojie.cn/thread-738504-1-1.html">https://www.52pojie.cn/thread-738504-1-1.html</a><br><a href="https://www.jb51.net/office/400628.html">https://www.jb51.net/office/400628.html</a><br><a href="https://www.jb51.net/softs/400621.html#downintro2">https://www.jb51.net/softs/400621.html#downintro2</a></p><h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><ul><li>office2016选择性安装：<a href="https://www.cnblogs.com/xxoome/p/7113412.html">https://www.cnblogs.com/xxoome/p/7113412.html</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;office2016在安装的时候并不像之前的版本有选择性的安装，安装器会安装一个office全家桶。那么如何自主选择安装自己需要的工具呢？&lt;/p&gt;</summary>
    
    
    
    <category term="software" scheme="http://next.skyheng.com/categories/software/"/>
    
    <category term="office" scheme="http://next.skyheng.com/categories/software/office/"/>
    
    
    <category term="office" scheme="http://next.skyheng.com/tags/office/"/>
    
  </entry>
  
  <entry>
    <title>OpenWrt 编译 LuCI -&gt; Applications 添加插件应用说明</title>
    <link href="http://next.skyheng.com/post/59643.html"/>
    <id>http://next.skyheng.com/post/59643.html</id>
    <published>2019-06-09T14:05:00.000Z</published>
    <updated>2025-11-30T14:41:25.906Z</updated>
    
    <content type="html"><![CDATA[<p>这个地方是写描述的地方</p><span id="more"></span><p>make menuconfig  进入定制界面<br>进入编译选项配置界面,.按照需要配置.( ‘*’ 代表编入固件，‘M’ 表示编译成模块或者IPK包， ‘空’不编译 )</p><p>选择LuCI –&gt; Applications配置：  常用</p><p>—————————————————————————————–<br>LuCI —&gt; Applications —&gt; luci-app-adbyby-plus   #去广告<br>LuCI —&gt; Applications —&gt; luci-app-arpbind  #IP&#x2F;MAC绑定<br>LuCI —&gt; Applications —&gt; luci-app-autoreboot  #支持计划重启<br>LuCI —&gt; Applications —&gt; luci-app-ddns   #动态域名<br>LuCI —&gt; Applications —&gt; luci-app-filetransfer  #文件传输<br>LuCI —&gt; Applications —&gt; luci-app-firewall   #添加防火墙<br>LuCI —&gt; Applications —&gt; luci-app-frpc   #FRP内网穿透<br>LuCI —&gt; Applications —&gt; luci-app-hd-idle  #硬盘休眠<br>LuCI —&gt; Applications —&gt; luci-app-ipsec-virtual<strong>d  #IPSec virtual</strong>服务<br>LuCI —&gt; Applications —&gt; luci-app-mwan3   #负载均衡<br>LuCI —&gt; Applications —&gt; luci-app-nlbwmon   #网络带宽监视器<br>LuCI —&gt; Applications —&gt; luci-app-p p t p-server  #p p t p virtual**服务<br>LuCI —&gt; Applications —&gt; luci-app-qos   #流量服务质量(QoS)<br>LuCI —&gt; Applications —&gt; luci-app-ramfree  #释放内存<br>LuCI —&gt; Applications —&gt; luci-app-samba   #网络共享(samba)<br>LuCI —&gt; Applications —&gt; luci-app-sfe  #Turbo ACC网络加速<br>LuCI —&gt; Applications —&gt; luci-app-sqm  #流量智能队列管理<br>LuCI —&gt; Applications —&gt; luci-app-S-S R-plus   #S-S R兲朝上网<br>LuCI —&gt; Applications —&gt; luci-app-syncdial  #多拨虚拟网卡(原macvlan)<br>LuCI —&gt; Applications —&gt; luci-app-upnp   #通用即插即用(UPnP)<br>LuCI —&gt; Applications —&gt; luci-app-v2ray-pro  #V2Ray透明代理<br>LuCI —&gt; Applications —&gt; luci-app-vlmcsd  #KMS服务器设置<br>LuCI —&gt; Applications —&gt; luci-app-vsftpd  #FTP服务器<br>LuCI —&gt; Applications —&gt; luci-app-webadmin  #Web管理页面设置<br>LuCI —&gt; Applications —&gt; luci-app-wifischedule  #WiFi 计划<br>LuCI —&gt; Applications —&gt; luci-app-wireless-regdb  #WiFi无线<br>LuCI —&gt; Applications —&gt; luci-app-wol   #网络唤醒<br>LuCI —&gt; Applications —&gt; luci-app-wrtbwmon  #客户端实时流量监测<br>LuCI —&gt; Applications —&gt; luci-app-xlnetacc  #迅雷快鸟<br>LuCI —&gt; Applications —&gt; luci-app-zerotier  #ZeroTier内网穿透<br>Utilities  —&gt;  open-vm-tools  #打开适用于VMware的VM Tools</p><p>—————————————————————————————–<br>LuCI —&gt; Applications —&gt; luci-app-adblock   #ADB广告过滤<br>LuCI —&gt; Applications —&gt; luci-app-adbyby   #广告过滤大师<br>LuCI —&gt; Applications —&gt; luci-app-advanced-reboot  #Linksys高级重启<br>LuCI —&gt; Applications —&gt; luci-app-ahcp  #支持AHCPd<br>LuCI —&gt; Applications —&gt; luci-app-aliddns   #阿里DDNS客户端<br>LuCI —&gt; Applications —&gt; luci-app-aria2 # Aria2下载<br>LuCI —&gt; Applications —&gt; luci-app-asterisk  #支持Asterisk<br>LuCI —&gt; Applications —&gt; luci-app-attendedsysupgrade  #固件相关<br>LuCI —&gt; Applications —&gt; luci-app-bcp38  #BCP38网络入口过滤(不确定)<br>LuCI —&gt; Applications —&gt; luci-app-bird4   #Bird 4(未知)<br>LuCI —&gt; Applications —&gt; luci-app-bird6   #Bird 6(未知)<br>LuCI —&gt; Applications —&gt; luci-app-bmx6  #协议相关(未知)<br>LuCI —&gt; Applications —&gt; luci-app-bmx7  #协议相关(未知)<br>LuCI —&gt; Applications —&gt; luci-app-cjdns  #CJDNS(未知)<br>LuCI —&gt; Applications —&gt; luci-app-clamav  #ClamAV杀毒软件<br>LuCI —&gt; Applications —&gt; luci-app-commands   #Shell命令模块<br>LuCI —&gt; Applications —&gt; luci-app-cshark   #CloudShark捕获工具<br>LuCI —&gt; Applications —&gt; luci-app-diag-core   #core诊断工具<br>LuCI —&gt; Applications —&gt; luci-app-dnscrypt-proxy  #DNSCrypt解决DNS污染<br>LuCI —&gt; Applications —&gt; luci-app-dump1090  #民航无线频率(不确定)<br>LuCI —&gt; Applications —&gt; luci-app-dynapoint  #DynaPoint(未知)<br>LuCI —&gt; Applications —&gt; luci-app-e2guardian   #Web内容过滤器<br>LuCI —&gt; Applications —&gt; luci-app-freifunk-diagnostics   #诊断(未知)<br>LuCI —&gt; Applications —&gt; luci-app-freifunk-policyrouting  #策略(未知)<br>LuCI —&gt; Applications —&gt; luci-app-freifunk-widgets  #索引(未知)<br>LuCI —&gt; Applications —&gt; luci-app-fwknopd  #Fwknop服务器<br>LuCI —&gt; Applications —&gt; luci-app-hnet  #HNCP家庭网络控制协议(不确定)<br>LuCI —&gt; Applications —&gt; luci-app-lxc   #LXC容器管理<br>LuCI —&gt; Applications —&gt; luci-app-meshwizard #网络设置向导<br>LuCI —&gt; Applications —&gt; luci-app-minidlna   #miniDLNA共享<br>LuCI —&gt; Applications —&gt; luci-app-mjpg-streamer   #添加视频监控<br>LuCI —&gt; Applications —&gt; luci-app-mmc-over-gpio   #添加SD卡操作界面<br>LuCI —&gt; Applications —&gt; luci-app-multiwan   #多拨虚拟网卡<br>LuCI —&gt; Applications —&gt; luci-app-n2n_v2   #N2N穿透内网<br>LuCI —&gt; Applications —&gt; luci-app-noddos  #阻止DDoS攻击<br>LuCI —&gt; Applications —&gt; luci-app-ntpc   #NTP时间同步服务器<br>LuCI —&gt; Applications —&gt; luci-app-ocserv  #OpenConnect virtual**<br>LuCI —&gt; Applications —&gt; luci-app-olsr  #OLSR配置和状态模块<br>LuCI —&gt; Applications —&gt; luci-app-olsr-services  #OLSR服务器<br>LuCI —&gt; Applications —&gt; luci-app-olsr-viz   #OLSR可视化<br>LuCI —&gt; Applications —&gt; luci-app-ocserv   #OpenConnect virtual<strong>服务<br>LuCI —&gt; Applications —&gt; luci-app-openvirtual</strong>  #Openvirtual<strong>客户端<br>LuCI —&gt; Applications —&gt; luci-app-openvirtual</strong>-server  #Openvirtual<strong>服务器<br>LuCI —&gt; Applications —&gt; luci-app-oscam   #OSCAM服务器<br>LuCI —&gt; Applications —&gt; luci-app-p910nd   #打印服务器模块<br>LuCI —&gt; Applications —&gt; luci-app-pagekitec   #Pagekite内网穿透客户端<br>LuCI —&gt; Applications —&gt; luci-app-polipo  #Polipo代理<br>LuCI —&gt; Applications —&gt; luci-app-privoxy  #Privoxy带过滤功能代理<br>LuCI —&gt; Applications —&gt; luci-app-radicale   #CalDAV&#x2F;CardDAV同步工具<br>LuCI —&gt; Applications —&gt; luci-app-rp-pppoe-server  #PPPoE 服务器<br>LuCI —&gt; Applications —&gt; luci-app-s-s-libes  #SS-libev服务端<br>LuCI —&gt; Applications —&gt; luci-app-shairplay  #支持AirPlay功能<br>LuCI —&gt; Applications —&gt; luci-app-siitwizard  #SIIT配置向导<br>LuCI —&gt; Applications —&gt; luci-app-simple-adblock  #简单的广告拦截<br>LuCI —&gt; Applications —&gt; luci-app-splash  #DHCP客户端应用<br>LuCI —&gt; Applications —&gt; luci-app-squid   #Squid代理服务器<br>LuCI —&gt; Applications —&gt; luci-app-s-s   #兲朝上网<br>LuCI —&gt; Applications —&gt; luci-app-S-S Rserver-python  #S-S R服务器-Python<br>LuCI —&gt; Applications —&gt; luci-app-statistics  #流量监控工具<br>LuCI —&gt; Applications —&gt; luci-app-tinyproxy  #TinyProxy 代理服务器<br>LuCI —&gt; Applications —&gt; luci-app-travelmate  #wlan连接管理器<br>LuCI —&gt; Applications —&gt; luci-app-transmission   #BT下载<br>LuCI —&gt; Applications —&gt; luci-app-udpxy  #udpxy做组播服务器<br>LuCI —&gt; Applications —&gt; luci-app-uhttpd  #uHTTPd Web服务器<br>LuCI —&gt; Applications —&gt; luci-app-unbound  #Unbound DNS解析器<br>LuCI —&gt; Applications —&gt; luci-app-usb-printer   #打印机TCP&#x2F;IP共享服务<br>LuCI —&gt; Applications —&gt; luci-app-vnstat   #vnStat流量查看&#x2F;监测工具<br>LuCI —&gt; Applications —&gt; luci-app-virtual</strong>bypass  #virtual** Bypass Web UI<br>LuCI —&gt; Applications —&gt; luci-app-watchcat  #断网检测功能<br>LuCI —&gt; Applications —&gt; luci-app-webshell  #网页命令行终端<br>LuCI —&gt; Applications —&gt; luci-app-wireguard  #WireGuard virtual**服务器<br>LuCI —&gt; Collections —&gt; luci   #添加luci (web界面管理)<br>LuCI —&gt; Modules —&gt; Translations —&gt; Simplified Chinese (zh-cn) #新版本中文语言包位置<br>LuCI —&gt; Themes —&gt; luci-theme-bootstrap   #默认主题<br>LuCI —&gt; Translations —&gt; luci-i18n-chinese   #添加luci的中文语言包<br>—————————————————————————————–</p><h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><p><a href="http://www.mm126.cc/314.html">openwrt-luci-app编译方式</a><a href="http://www.mm126.cc/314.html">http://www.mm126.cc/314.html</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个地方是写描述的地方&lt;/p&gt;</summary>
    
    
    
    <category term="software" scheme="http://next.skyheng.com/categories/software/"/>
    
    <category term="openwrt" scheme="http://next.skyheng.com/categories/software/openwrt/"/>
    
    
    <category term="openwrt" scheme="http://next.skyheng.com/tags/openwrt/"/>
    
  </entry>
  
  <entry>
    <title>MySql免安装版安装方法与配置调整</title>
    <link href="http://next.skyheng.com/post/36645.html"/>
    <id>http://next.skyheng.com/post/36645.html</id>
    <published>2019-05-30T01:50:56.000Z</published>
    <updated>2025-11-30T14:41:25.906Z</updated>
    
    <content type="html"><![CDATA[<p>需要使用MySQL，想起免安装版，遂再安装一遍MySQL，但是我好像没有记录怎么在win版下怎么安装的，之前安装都是需要安装的使用又去百度，今天我就记录下我的安装过程。以便以后进行查阅。</p><span id="more"></span><p>第1步：下载如下图安装包</p><p><img data-src="http://qn.blog.skyheng.com/img/051046144771907.png" alt="img"></p><p>第2步：解压mysql压缩包，然后进入解压后的安装包</p><p><img data-src="http://qn.blog.skyheng.com/img/051049372115270.png" alt="img"></p><p>将my-default.ini复制一份，并改名为my.ini(我已经完成）</p><p>把下面内容复制到my.ini,并保存</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[client]</span></span><br><span class="line"><span class="attr">port</span>=<span class="number">3306</span></span><br><span class="line"><span class="attr">default-character-set</span>=utf8</span><br><span class="line"></span><br><span class="line"><span class="comment">#客户端字符类型，与服务端一致就行，建议utf8</span></span><br><span class="line"></span><br><span class="line"><span class="section">[mysqld]</span></span><br><span class="line"></span><br><span class="line"><span class="attr">port</span>=<span class="number">3306</span></span><br><span class="line"><span class="attr">character_set_server</span>=utf8</span><br><span class="line"></span><br><span class="line"><span class="comment">#服务端字符类型，建议utf8</span></span><br><span class="line"></span><br><span class="line"><span class="attr">basedir</span>=C:\mysql-<span class="number">5.6</span>.<span class="number">44</span>-winx64</span><br><span class="line"><span class="comment">#解压根目录(skip-grant-tables,更改密码，加skip-grant-tables，停服务,起服务，update ,停服务,注skip-grant-tables，起服务)</span></span><br><span class="line"></span><br><span class="line"><span class="attr">datadir</span>=C:\mysql-<span class="number">5.6</span>.<span class="number">44</span>-winx64\data</span><br><span class="line"><span class="comment">#skip-grant-tables</span></span><br><span class="line"><span class="comment">#解压根目录\data</span></span><br><span class="line"></span><br><span class="line"><span class="attr">performance_schema_max_table_instances</span>=<span class="number">200</span></span><br><span class="line"><span class="attr">table_definition_cache</span>=<span class="number">200</span></span><br><span class="line"><span class="attr">table_open_cache</span>=<span class="number">128</span></span><br><span class="line"></span><br><span class="line"><span class="attr">sql_mode</span>=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES</span><br><span class="line"></span><br><span class="line"><span class="section">[WinMySQLAdmin]</span></span><br><span class="line"></span><br><span class="line">C:\mysql-5.6.44-winx64\bin\mysqld.exe</span><br><span class="line"></span><br><span class="line"><span class="comment">#解压根目录\bin\mysqld.exe</span></span><br></pre></td></tr></table></figure><h3 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h3><ul><li><a href="https://blog.csdn.net/sz_bdqn/article/details/50813385">MySQL 5.6内存占用过高解决方案</a></li><li><a href="https://blog.csdn.net/qq_37674858/article/details/80047991">解决mySQL占用内存超大问题</a></li><li><a href="https://www.cnblogs.com/musings/p/5913225.html">mysql5.6启动占用内存很大的解决方法</a></li></ul><h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><ul><li><a href="https://www.cnblogs.com/feilongblog/p/mysql_install_init.html">MySql免安装版配置方法</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;需要使用MySQL，想起免安装版，遂再安装一遍MySQL，但是我好像没有记录怎么在win版下怎么安装的，之前安装都是需要安装的使用又去百度，今天我就记录下我的安装过程。以便以后进行查阅。&lt;/p&gt;</summary>
    
    
    
    <category term="software" scheme="http://next.skyheng.com/categories/software/"/>
    
    <category term="mysql" scheme="http://next.skyheng.com/categories/software/mysql/"/>
    
    
    <category term="mysql" scheme="http://next.skyheng.com/tags/mysql/"/>
    
  </entry>
  
  <entry>
    <title>Spring Boot之版本更新的配置变动</title>
    <link href="http://next.skyheng.com/post/23579.html"/>
    <id>http://next.skyheng.com/post/23579.html</id>
    <published>2019-05-23T07:52:15.000Z</published>
    <updated>2025-11-30T14:41:25.871Z</updated>
    
    <content type="html"><![CDATA[<p>Spring Boot的版本升级带来的配置及特性都有发生改变，搭建框架时碰到，特此记录</p><span id="more"></span><p><img data-src="/2019-05-23.Spring-Boot%E4%B9%8B%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E7%9A%84%E9%85%8D%E7%BD%AE%E5%8F%98%E5%8A%A8.assets/image-20200530230419183.png" alt="image-20200530230419183"></p><h2 id="打印RequestMapping信息配置"><a href="#打印RequestMapping信息配置" class="headerlink" title="打印RequestMapping信息配置"></a>打印RequestMapping信息配置</h2><h3 id="2-1之前的版本"><a href="#2-1之前的版本" class="headerlink" title="2.1之前的版本"></a>2.1之前的版本</h3><p>Spring Boot 2.1 之前 使用INFO 级别记录的信息很多，所以只需要配置为INFO程序启动的时候就可以打印 RequestMapping 的信息，示例如下：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">level:</span></span><br><span class="line">    <span class="attr">root:</span> <span class="string">info</span></span><br></pre></td></tr></table></figure><p>打印出来的格式如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">2019-05-23 16:51:45.824  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/board/add]&#125;&quot; onto public com.ztd.question.util.ResultVo com.ztd.question.web.controller.BoardController.add(com.ztd.question.web.entity.Board)</span><br><span class="line">2019-05-23 16:51:45.826  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/board/update]&#125;&quot; onto public com.ztd.question.util.ResultVo com.ztd.question.web.controller.BoardController.update(com.ztd.question.web.entity.Board)</span><br><span class="line">2019-05-23 16:51:45.827  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/board/saveList]&#125;&quot; onto public com.ztd.question.util.ResultVo com.ztd.question.web.controller.BoardController.update(com.ztd.question.web.entity.Board[])</span><br><span class="line">2019-05-23 16:51:45.827  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/board/delete/&#123;id&#125;]&#125;&quot; onto public com.ztd.question.util.ResultVo com.ztd.question.web.controller.BoardController.delete(java.lang.Integer)</span><br><span class="line">2019-05-23 16:51:45.828  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/board/list]&#125;&quot; onto public com.ztd.question.util.ResultVo&lt;java.util.List&lt;com.ztd.question.web.entity.Board&gt;&gt; com.ztd.question.web.controller.BoardController.list(java.lang.String)</span><br><span class="line">2019-05-23 16:51:45.830  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/index],methods=[GET]&#125;&quot; onto public java.lang.String com.ztd.question.web.controller.IndexController.homePage()</span><br><span class="line">2019-05-23 16:51:45.831  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/order/create]&#125;&quot; onto public com.ztd.question.util.ResultVo&lt;java.lang.Object&gt; com.ztd.question.web.controller.RetryController.list(java.lang.Integer) throws java.lang.Exception</span><br><span class="line">2019-05-23 16:51:45.834  INFO 13218 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped &quot;&#123;[/error]&#125;&quot; onto public org.springframework.http.ResponseEntity&lt;java.util.Map&lt;java.lang.String, java.lang.Object&gt;&gt; org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)</span><br></pre></td></tr></table></figure><h3 id="2-1之后的版本"><a href="#2-1之后的版本" class="headerlink" title="2.1之后的版本"></a>2.1之后的版本</h3><p>Spring Boot 2.1 以后 使用了 Spring Framework 5.1, 而 Spring Framework 5.1 对日志做了较大的改动。现在使用 INFO 级别记录的信息非常少，DEBUG 级别提供了更多信息，但不详细。只有 TRACE 级别才会提供详细信息。这时候为了要打印Controller里面的 RequestMapping信息需要把org.springframework.web打印日志的格式设置为trace，示例如下：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">level:</span></span><br><span class="line">    <span class="attr">root:</span> <span class="string">info</span></span><br><span class="line">    <span class="attr">org.mybatis:</span> <span class="string">debug</span></span><br><span class="line">    <span class="attr">java.sql:</span> <span class="string">debug</span></span><br><span class="line">    <span class="attr">org.springframework.web:</span> <span class="string">trace</span></span><br></pre></td></tr></table></figure><p>日志输出格式如下：把每个Controller下面的所有RequestMapping全部列到一个Controller下面，打印格式比之前的格式可读性和区分性更好一些</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span>-<span class="number">05</span>-<span class="number">23</span> <span class="number">16</span>:<span class="number">55</span>:<span class="number">22.241</span> TRACE <span class="number">13313</span> --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : </span><br><span class="line">c.z.q.w.c.BoardController:</span><br><span class="line">&#123; /board/add&#125;: add(Board)</span><br><span class="line">&#123; /board/update&#125;: update(Board)</span><br><span class="line">&#123; /board/saveList&#125;: update(Board[])</span><br><span class="line">&#123; /board/delete/&#123;id&#125;&#125;: delete(Integer)</span><br><span class="line">&#123; /board/list&#125;: list(String)</span><br><span class="line"><span class="number">2019</span>-<span class="number">05</span>-<span class="number">23</span> <span class="number">16</span>:<span class="number">55</span>:<span class="number">22.247</span> TRACE <span class="number">13313</span> --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : </span><br><span class="line">c.z.q.w.c.IndexController:</span><br><span class="line">&#123;GET /index&#125;: homePage()</span><br><span class="line"><span class="number">2019</span>-<span class="number">05</span>-<span class="number">23</span> <span class="number">16</span>:<span class="number">55</span>:<span class="number">22.248</span> TRACE <span class="number">13313</span> --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : </span><br><span class="line">c.z.q.w.c.RetryController:</span><br><span class="line">&#123; /order/create&#125;: list(Integer)</span><br><span class="line"><span class="number">2019</span>-<span class="number">05</span>-<span class="number">23</span> <span class="number">16</span>:<span class="number">55</span>:<span class="number">22.253</span> TRACE <span class="number">13313</span> --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : </span><br><span class="line">o.s.b.a.w.s.e.BasicErrorController:</span><br><span class="line">&#123; /error&#125;: error(HttpServletRequest)</span><br><span class="line">&#123; /error, produces [text/html]&#125;: errorHtml(HttpServletRequest,HttpServletResponse)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;Spring Boot的版本升级带来的配置及特性都有发生改变，搭建框架时碰到，特此记录&lt;/p&gt;</summary>
    
    
    
    <category term="java" scheme="http://next.skyheng.com/categories/java/"/>
    
    <category term="springBoot" scheme="http://next.skyheng.com/categories/java/springBoot/"/>
    
    
    <category term="java" scheme="http://next.skyheng.com/tags/java/"/>
    
    <category term="springBoot" scheme="http://next.skyheng.com/tags/springBoot/"/>
    
  </entry>
  
</feed>
