<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>披萨盒的赛博日志</title>
  <icon>https://blog.pushihao.com/img/favicon.png</icon>
  <subtitle>热水比冷水更快结冰</subtitle>
  <link href="https://blog.pushihao.com/atom.xml" rel="self"/>
  
  <link href="https://blog.pushihao.com/"/>
  <updated>2025-06-15T01:53:50.000Z</updated>
  <id>https://blog.pushihao.com/</id>
  
  <author>
    <name>披萨盒</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>像 systemd 一样管理 MacOS 后台常驻任务</title>
    <link href="https://blog.pushihao.com/article/e1b388df.html"/>
    <id>https://blog.pushihao.com/article/e1b388df.html</id>
    <published>2025-06-14T09:46:29.000Z</published>
    <updated>2025-06-15T01:53:50.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>想在 MacOS 后台跑一个 frp 服务，想到 MacOS 是类 Unix 系统所以应该跟 Linux 差不多，自然而然的想到使用 systemd 将 frp 服务作为守护进程管理。然鹅输入<code>vim /etc/systemd/sys</code>之后按了半天 tab 都不自动补全为<code>vim /etc/systemd/system</code>，一看<code>/etc</code>目录下压根就没有<code>systemd</code>这个目录。上网一搜才知道 MacOS 压根就没有 systemd，取而代之的是 launchd。既然都提到了，就简要介绍一下吧。</p><h2 id="起源"><a href="#起源" class="headerlink" title="起源"></a>起源</h2><p>传统的 Linux 系统使用 System V init 或 BSD init 作为系统的第一个进程，负责启动其他服务和进程。随着系统复杂性的增加，这些 init 系统暴露出一些缺点，比如串行启动服务、启动速度慢等。</p><p>随后，upstart 项目引入了并行启动服务等概念用以解决 System V init 存在的问题，但仍然存在一些限制。</p><p>接着，systemd 诞生了，它提供更高效、更灵活的系统启动和管理方式。但是由于 systemd 使用了 <a href="https://en.wikipedia.org/wiki/Cgroups">cgroups</a> 等组件以实现其特性，所以只适用于Linux。</p><p>苹果系统是闭源的，但是 launchd 却是开源的，还挺有意思。其最早由 Dave Zarzycki 等人创建，并在Mac OS X Tiger（10.4版本）中首次引入，用于替代传统的 init 脚本、SystemStarter 以及其他一些服务管理工具，如 inetd、atd 和 crond 等。</p><h2 id="systemd-实战入门"><a href="#systemd-实战入门" class="headerlink" title="systemd 实战入门"></a>systemd 实战入门</h2><p>在本节中，我们首先通过一个小🌰来入门 systemd，然后接下来给出 service 文件（核心）的详细说明。</p><h3 id="小例子：后台记录时间"><a href="#小例子：后台记录时间" class="headerlink" title="小例子：后台记录时间"></a>小例子：后台记录时间</h3><p>一、首先我们需要编写一个需要后台运行的脚本，这里以每10秒输出一次时间的脚本<code>/root/bin/systemd_test.sh</code>为例，内容如下</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">while true; do</span><br><span class="line">    CURRENT_TIME=$(date +&quot;%Y-%m-%d %H:%M:%S&quot;)</span><br><span class="line">    echo &quot;$CURRENT_TIME&quot;</span><br><span class="line">    sleep 10</span><br><span class="line">done</span><br></pre></td></tr></table></figure><p>二、赋予脚本可执行权限</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x /root/bin/systemd_test.sh</span><br></pre></td></tr></table></figure><p>三、先执行一下看看有没有问题</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506141922542.png" alt="image-20250614192113838"></p><p>四、创建 systemd 服务文件</p><p>在<code>/etc/systemd/system/</code>目录下创建一个服务文件，名字随意，但必须以<code>.service</code>结尾，本示例为<code>/etc/systemd/system/record_time.service</code>，内容如下</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></pre></td><td class="code"><pre><span class="line"><span class="section">[Unit]</span></span><br><span class="line"><span class="attr">Description</span>=Record Time Service</span><br><span class="line"><span class="attr">After</span>=network.target</span><br><span class="line"></span><br><span class="line"><span class="section">[Service]</span></span><br><span class="line"><span class="attr">Type</span>=simple</span><br><span class="line"><span class="attr">ExecStart</span>=/root/bin/systemd_test.sh</span><br><span class="line"><span class="attr">Restart</span>=<span class="literal">on</span>-failure</span><br><span class="line"><span class="attr">RestartSec</span>=<span class="number">10</span>s</span><br><span class="line"><span class="attr">StandardOutput</span>=append:/var/log/record_time/output.log</span><br><span class="line"><span class="attr">StandardError</span>=append:/var/log/record_time/error.log</span><br><span class="line"></span><br><span class="line"><span class="section">[Install]</span></span><br><span class="line"><span class="attr">WantedBy</span>=multi-user.target</span><br></pre></td></tr></table></figure><p>五、执行如下命令即可启动服务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">systemctl daemon-reload</span><br><span class="line">systemctl start record_time   <span class="comment"># 启动服务</span></span><br><span class="line">systemctl <span class="built_in">enable</span> record_time  <span class="comment"># 设置服务开机自动启动</span></span><br></pre></td></tr></table></figure><p>成功运行示例如下</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506141950834.png" alt="image-20250614195034781"></p><p>如果启动失败，可以使用命令<code>journalctl -u record_time</code>查看失败日志。比如我最开始就因为忘记创建<code>/var/log/record_time</code>目录导致启动失败了😂</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506141953304.png" alt="image-20250614195313254"></p><h3 id="service-文件详解"><a href="#service-文件详解" class="headerlink" title="service 文件详解"></a>service 文件详解</h3><p>看到网上有一篇介绍 service 文件如何编写的文章 <a href="https://zh.opensuse.org/openSUSE:How_to_write_a_systemd_service#">OpenSUSE: How to write a systemd service</a>，已经写的很通俗很详细了，这里就不重复造轮子了。</p><h3 id="用户级-systemd"><a href="#用户级-systemd" class="headerlink" title="用户级 systemd"></a>用户级 systemd</h3><p>上面我们给出的例子是需要管理员权限的，普通用户是无法在<code>/etc/systemd/system</code>目录下创建<code>.service</code>文件的</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506142022341.png" alt="image-20250614202237287"></p><p>但是我们可以在自己的用户目录下创建，具体的目录为<code>~/.config/systemd/user/xxx.service</code>，service 文件的内容和普通 service 文件是相同的，相应的管理命令也稍有不同（需要加上<code>--user</code>参数），如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">systemctl --user daemon-reload</span><br><span class="line">systemctl --user start record_time   <span class="comment"># 启动服务</span></span><br><span class="line">systemctl --user <span class="built_in">enable</span> record_time  <span class="comment"># 设置用户登录后自动启动</span></span><br></pre></td></tr></table></figure><p>有一点比较坑的是执行<code>systemctl --user enable xxx</code>后的后台守护进程只在用户登录后运行，用户<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">loginctl enable-linger &lt;username&gt;    <span class="comment"># 启动逗留状态</span></span><br><span class="line">loginctl disable-linger &lt;username&gt;   <span class="comment"># 关闭逗留状态</span></span><br></pre></td></tr></table></figure><h2 id="launchd-实战入门"><a href="#launchd-实战入门" class="headerlink" title="launchd 实战入门"></a>launchd 实战入门</h2><p>同上，我们仍然是先给出一个例子，然后再给出具体解释。</p><h3 id="例子：后台记录时间"><a href="#例子：后台记录时间" class="headerlink" title="例子：后台记录时间"></a>例子：后台记录时间</h3><p>(没错，还是这个例子，我们主要关注操作方式与 systemd 的不同)</p><p>一、编写脚本<code>~/Scripts/launchd_test.sh</code>，内容如下</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">while true; do</span><br><span class="line">    CURRENT_TIME=$(date +&quot;%Y-%m-%d %H:%M:%S&quot;)</span><br><span class="line">    echo &quot;$CURRENT_TIME&quot;</span><br><span class="line">    sleep 10</span><br><span class="line">done</span><br></pre></td></tr></table></figure><p>二、赋予脚本可执行权限</p><figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x launchd_test.sh</span><br></pre></td></tr></table></figure><p>三、先执行一下，看看有没有问题</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506142018039.png" alt="image-20250614201839000"></p><p>四、创建 plist 配置文件</p><p>在<code>~/Library/LaunchAgents</code>目录下创建一个服务文件，名字随意，但必须以<code>.plist</code>结尾，本示例为<code>~/Library/LaunchAgents/com.pushihao.record_time.plist</code>，内容如下</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">plist</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//Apple//DTD PLIST 1.0//EN&quot;</span> <span class="string">&quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plist</span> <span class="attr">version</span>=<span class="string">&quot;1.0&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dict</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>Label<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">string</span>&gt;</span>com.pushihao.record_time<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>ProgramArguments<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">array</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">string</span>&gt;</span>/Users/itgrape/Scripts/launchd_test.sh<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">array</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>RunAtLoad<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">true</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>KeepAlive<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">true</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>StandardOutPath<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">string</span>&gt;</span>/Users/itgrape/logs/record_time/output.log<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>StandardErrorPath<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">string</span>&gt;</span>/Users/itgrape/logs/record_time/error.log<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>WorkingDirectory<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">string</span>&gt;</span>/Users/itgrape/Scripts/<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">dict</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plist</span>&gt;</span></span><br></pre></td></tr></table></figure><p>五、加载&#x2F;卸载服务</p><p>旧：</p><figure class="highlight zsh"><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">launchctl load ~/Library/LaunchAgents/com.pushihao.record_time.plist    <span class="comment"># 加载服务</span></span><br><span class="line">launchctl unload ~/Library/LaunchAgents/com.pushihao.record_time.plist  <span class="comment"># 卸载服务</span></span><br></pre></td></tr></table></figure><p>新（更推荐）：</p><figure class="highlight zsh"><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">launchctl bootstrap gui/$(<span class="built_in">id</span> -u) ~/Library/LaunchAgents/com.pushihao.record_time.plist    <span class="comment"># 在用户 GUI 域中注册服务</span></span><br><span class="line">launchctl bootout gui/$(<span class="built_in">id</span> -u) ~/Library/LaunchAgents/com.pushihao.record_time.plist      <span class="comment"># 从用户 GUI 域中卸载服务</span></span><br></pre></td></tr></table></figure><p>六、执行命令启动服务</p><figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">launchctl list | grep com.pushihao.record_time            <span class="comment"># 检查服务是否被加载</span></span><br><span class="line">launchctl start com.pushihao.record_time                  <span class="comment"># 启动已加载服务</span></span><br><span class="line">launchctl stop com.pushihao.record_time                   <span class="comment"># 停止服务</span></span><br><span class="line">launchctl <span class="built_in">enable</span> gui/$(<span class="built_in">id</span> -u)/com.pushihao.record_time    <span class="comment"># 设置用户登录自动启动（bootstrap 后默认开启）</span></span><br><span class="line">launchctl <span class="built_in">disable</span> gui/$(<span class="built_in">id</span> -u)/com.pushihao.record_time   <span class="comment"># 关闭用户登录自动启动</span></span><br></pre></td></tr></table></figure><div class="note warning flat"><p>注意：因为 KeepAlive 设置为 true，所以手动 stop 后，launchd 可能很快会再次尝试启动。要想永久停止，需要使用上述卸载服务的 unload&#x2F;bootout 命令。</p></div><p>成功运行示例如下</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506142057832.png" alt="image-20250614205709768"></p><p>还会弹出个这玩意</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202506142101237.png" alt="image-20250614210112192"></p><h3 id="plist-文件解释"><a href="#plist-文件解释" class="headerlink" title="plist 文件解释"></a>plist 文件解释</h3><p>这里去看 Apple 的官方文档即可 <a href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html">Daemons and Services Programming Guide</a>，它介绍的已经非常详细了。这里就简要介绍一下上面例子中各配置项的作用。</p><ul><li><code>Label</code>: 服务的唯一标识符，<code>launchctl</code>命令会用到它。</li><li><code>ProgramArguments</code>: 要执行的命令和参数。数组的第一个字符串是要执行脚本的<strong>绝对路径</strong>。</li><li><code>RunAtLoad</code>: <code>&lt;true/&gt;</code>表示当服务被加载时立即启动。</li><li><code>KeepAlive</code>: <code>&lt;true/&gt;</code>这是实现长期运行的关键！如果设为<code>true</code>，<code>launchd</code>会监视该进程，一旦它退出（无论是因为错误崩溃还是正常结束），<code>launchd</code>会立刻重新启动它。</li><li><code>StandardOutPath</code>: (可选) 重定向标准输出（脚本中<code>echo</code>的内容）到指定文件。</li><li><code>StandardErrorPath</code>: (可选) 重定向标准错误到指定文件。这对于排查脚本错误至关重要。</li><li><code>WorkingDirectory</code>: (可选) 设置脚本运行前的工作目录。</li></ul><h3 id="系统级-launchd"><a href="#系统级-launchd" class="headerlink" title="系统级 launchd"></a>系统级 launchd</h3><p>注意看，这里我的介绍顺序是和 systemd 是反着的。systemd 我给出的例子是系统级，随后我又给出了用户级 systemd 的使用方法。而该 launchd 的例子我给出的是用户级，接下来我介绍一下系统级 launchd 的使用。</p><div class="note warning flat"><p>注意：上面我们已经提到了旧版和新版的加载&#x2F;卸载命令，他们对应的用户级&#x2F;系统级 launchd 的使用方式也是不同的。</p></div><p><strong>旧版 load&#x2F;unload 命令</strong>：</p><p>其区别主要在于 plist 文件的存放位置，系统级 launchd 的 .plist 文件放在<code>/Library/LaunchDaemons/</code>目录下，而用户级 launchd 的 .plist 文件放在<code>~/Library/LaunchAgents/</code>或<code>/Library/LaunchAgents/</code>目录下。他们之间的区别如下：</p><p><strong><code>~/Library/LaunchAgents</code></strong></p><ul><li>启动时机：仅当<strong>特定用户登录</strong>时启动。</li><li>运行权限：以<strong>当前用户</strong>的权限运行。</li><li>访问GUI：可以。因为它们在用户的图形会话中运行，所以这些任务可以创建窗口、显示菜单栏图标或执行其他与用户界面交互的操作。</li><li>适用场景：适用于仅当前用户需要的服务，例如个人的定时任务或用户特定的后台程序。</li></ul><p><strong><code>/Library/LaunchAgents</code></strong></p><ul><li>启动时机：当<strong>任何用户登录</strong>时启动。</li><li>运行权限：以<strong>当前登录用户</strong>的权限运行。</li><li>访问GUI：可以。同上。</li><li>适用场景：适用于所有用户共用的用户级服务，例如某些需要在用户登录时启动的系统服务。</li></ul><p><strong><code>/Library/LaunchDaemons</code></strong></p><ul><li>启动时机：在<strong>系统启动时</strong>运行，<strong>无需用户登录</strong>。</li><li>运行权限：通常以<strong>root用户</strong>的权限运行，但也可以指定其他用户。</li><li>访问GUI：<strong>不可以</strong>。因为它们独立于任何用户，所以它们无法（也不应该）与用户界面进行任何交互。</li><li>适用场景：适用于需要在系统启动时运行的与用户无关的全局服务，例如网络服务、数据库服务等。</li></ul><p>除此之外，<code>/System/Library/LaunchDaemons/</code>和<code>/System/Library/LaunchAgents/</code>目录下也会保存有一些<code>.plist</code>文件，这些文件是由苹果系统提供的系统守护进程或用户代理。一般不要动它们。</p><p><strong>新版 bootstrap&#x2F;bootout 命令</strong>：</p><p>bootstrap 与旧的 load 命令最大的不同在于明确性。</p><ul><li><p>launchctl load（旧方式）通过<code>.plist</code>文件的存放路径来推断我们想要将服务注册到哪个域。这种方式比较模糊，依赖于文件路径的约定，现在苹果官方已不推荐在新的脚本中使用。</p></li><li><p>launchctl bootstrap（新方式）强制要求我们必须明确指定要注册到哪个域，命令本身就包含了所有信息，不再依赖于文件路径来做判断。这种方式更清晰、更精确，减少了歧义，是目前官方推荐的方式。</p></li></ul><p>通过域信息，我们就可以指定该任务是在哪个级别下运行了。域信息如下</p><ul><li>system 域：类似于老方式的<code>/Library/LaunchDaemons</code>。</li><li>gui&lt;uid&gt; 域：在指定用户登录后创建的图形会话中运行，类似于老方式下的<code>~/Library/LaunchAgents</code>。</li><li>user&lt;uid&gt; 域，用于注册指定用户后台代理，但不提供GUI访问权限。</li></ul><p>虽说使用了新版方式后理论上<code>.plist</code>文件可以放在任何位置，但是由于系统启动或用户登录时 launchd 进程只会去扫描一组预先定义好的、受信任的标准目录（也就是我们上面所说的5个目录）而并不会去扫描整个硬盘来寻找所有<code>.plist</code>文件。因此如果我们的<code>.plist</code>文件放在一个自定义目录（比如<code>/Users/itgrape/Launchd/</code>），那么在扫描阶段，launchd 根本就不会去查看那个目录，因此它永远发现不了我们的服务，这也就导致了 enable 可能会失效。兼容起见，还是放在上面我提到的三个目录其中之一里面吧。</p><p>在读完了上述章节之后，相信读者也已经对 systemd 和 launchd 的基本使用有了一定的了解。接下来我们在设计层面比较一下他们之间的差异。</p><h2 id="两大体系对比"><a href="#两大体系对比" class="headerlink" title="两大体系对比"></a>两大体系对比</h2><p>它们虽然干着类似的活儿——管理那些开机启动的、默默在后台运行的服务（守护进程），以及响应各种事件触发任务，但它们两个的设计理念以及工作方式却大不相同。</p><h3 id="启动方式"><a href="#启动方式" class="headerlink" title="启动方式"></a>启动方式</h3><p>Launchd：按需启动</p><ul><li>Mac 上有很多服务（比如打印服务、文件共享服务等）。默认按需启动，也就是说 Launchd 让这些服务平时都在“睡觉”，节省资源。只有当真正有人或系统事件需要它时（比如我们点了“打印”，或者有个网络连接请求进来），它才会迅速唤醒对应的服务。服务干完活，如果没特别要求，它就又回去“睡觉”了。这样电脑就能又快（响应我们的操作时快）又省电。除非指定了 KeepAlive 为 true，服务才会一直运行。</li></ul><p>Systemd：开机并行驱动</p><ul><li>它首要目标就是让 Linux 开机速度大大加快。怎么做到？不是按需启动，而是并行启动。分析好各个服务之间的依赖关系（谁先启动谁后启动），然后尽可能多同时启动没有依赖冲突的服务。结果就是：系统整体启动嘎嘎快。</li></ul><h3 id="文件组织"><a href="#文件组织" class="headerlink" title="文件组织"></a>文件组织</h3><p>Launchd：所有配置全放在<code>.plist</code>文件（一种 XML 或二进制格式的文件）里。这个文件描述了服务叫什么名字（Label）、启动命令是什么（ProgramArguments）、监听什么事件（Sockets, WatchPaths, StartCalendarInterval）、要不要一直跑（KeepAlive）等等。简单来说，就这一种文件。</p><p>Systemd：配置是按单元（Unit）分的（<code>.ini</code>风格），有不同的类型，每种单元单独写一个文件：</p><ul><li><code>.service</code>：定义要运行的后台服务本身（启动命令、重启策略等）。</li><li><code>.socket</code>：定义监听一个网络端口或 Unix Socket（用来按需启动服务）。</li><li><code>.timer</code>：定义定时任务（替代 cron）。</li><li><code>.path</code>：定义监控文件或目录变化（变化了启动服务）。</li><li><code>.target</code>：定义一组单元（类似传统 Linux 的运行级别）。</li><li>… 其他（<code>.mount</code>, <code>.slice</code> 等）。</li></ul><h3 id="日志查看"><a href="#日志查看" class="headerlink" title="日志查看"></a>日志查看</h3><p>Launchd：服务自己决定日志写哪。</p><p>Systemd：它自己带了个日志系统叫 journald。所有由 systemd 管理的服务的日志（包括它们的输出信息），默认都统一收拢到这里。然后用<code>journalctl</code>命令就能查、过滤、跟踪所有服务的日志。</p><h2 id="快速参考备忘录"><a href="#快速参考备忘录" class="headerlink" title="快速参考备忘录"></a>快速参考备忘录</h2><p>接下来我将用一个清晰的表格概括 systemd 和 launchd 的使用。</p><p>表格中<code>...</code>表示带后缀的配置文件的绝对路径。</p><table><thead><tr><th align="left">功能</th><th>systemd (Linux)</th><th>launchd (macOS)</th></tr></thead><tbody><tr><td align="left">配置文件</td><td>&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;my-app.service</td><td>~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.me.myapp.plist</td></tr><tr><td align="left">启用并立即启动</td><td>sudo systemctl enable –now my-app</td><td>launchctl load … | launchctl bootstrap …</td></tr><tr><td align="left">禁用并停止</td><td>sudo systemctl disable –now my-app</td><td>launchctl unload … | launchctl bootout …</td></tr><tr><td align="left">启动服务</td><td>sudo systemctl start my-app</td><td>launchctl start com.me.myapp</td></tr><tr><td align="left">停止服务</td><td>sudo systemctl stop my-app</td><td>launchctl stop com.me.myapp</td></tr><tr><td align="left">查看服务状态</td><td>sudo systemctl status my-app</td><td>launchctl list</td></tr><tr><td align="left">查看日志</td><td>sudo journalctl -u my-app -f</td><td>tail -f &#x2F;path&#x2F;to&#x2F;your.log</td></tr><tr><td align="left">重载配置</td><td>sudo systemctl daemon-reload</td><td>需要先 unload 再 load</td></tr></tbody></table><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>systemd 使用于 Linux，而 launchd 适用于 MacOS，并非替代关系。</p>]]></content>
    
    
    <summary type="html">如何让一个程序或脚本在 macOS 上像服务一样，能够开机自启、稳定运行、自动重启？针对此问题，本文将简要介绍 Linux 世界的王者 systemd 和 MacOS 平台下 “官方指定” 的解决方案 launchd...</summary>
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="MacOS" scheme="https://blog.pushihao.com/tags/MacOS/"/>
    
    <category term="Launchd" scheme="https://blog.pushihao.com/tags/Launchd/"/>
    
    <category term="Systemd" scheme="https://blog.pushihao.com/tags/Systemd/"/>
    
    <category term="守护进程" scheme="https://blog.pushihao.com/tags/%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>以ORM看封装的边界</title>
    <link href="https://blog.pushihao.com/article/4796bcfa.html"/>
    <id>https://blog.pushihao.com/article/4796bcfa.html</id>
    <published>2025-05-30T09:11:28.000Z</published>
    <updated>2025-05-30T09:11:28.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>今天在看<a href="https://chai2010.cn/advanced-go-programming-book/ch5-web/ch5-05-database.html">《Go语言高级编程》</a>这本书，注意到作者在谈论 ORM 框架时提到了两句话 </p><ol><li>“喜欢强类型语言的人一般都不喜欢语言隐式地去做什么事情，例如各种语言在赋值操作时进行的隐式类型转换然后又在转换中丢失了精度的勾当，一定让你非常的头疼。所以一个程序库背地里做的事情还是越少越好，如果一定要做，那也一定要在显眼的地方做”</li><li>“但这样的分析想证明的是，ORM 想从设计上隐去太多的细节。而方便的代价是其背后的运行完全失控。这样的项目在经过几任维护人员之后，将变得面目全非，难以维护”</li></ol><p>我看到这两段话时第一时间想到的是面向对象程序设计语言中的封装以及高级编程语言对低级编程语言的抽象。封装实现的不就是隐藏功能的内部实现细节，只将使用方式暴露出来？而高级编程语言相较于底层编程语言（比如汇编）的进步不也就是对细节的隐藏？</p><p>但我仔细一想，也不是这么回事。经过一番查阅资料后，我觉得他们还是有本质区别的，关键在于“隐藏什么”以及“隐藏的代价”是否可控和透明。</p><h2 id="辨析1-封装-vs-ORM"><a href="#辨析1-封装-vs-ORM" class="headerlink" title="辨析1: 封装 vs ORM"></a>辨析1: 封装 vs ORM</h2><p>封装隐藏的是模块内部的实现细节（数据存储方式、具体算法步骤等）。它提供的是一个清晰、稳定、语义明确的接口。使用者通过接口调用功能，无需关心内部如何完成。接口本身是显式的、强类型的，调用行为是可控的、可预测的。封装的目的是降低耦合、提高内聚、增强安全性。它并没有试图改变或掩盖操作本身的本质语义。</p><p>ORM 的问题就在于它试图隐藏的往往是操作本身的本质和关键细节，甚至与数据库交互的语义都有可能被改变。<a href="https://chai2010.cn/advanced-go-programming-book/ch5-web/ch5-05-database.html">《Go语言高级编程》</a>这本书的作者还举了一个例子：</p><figure class="highlight go"><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">o := orm.NewOrm()</span><br><span class="line">num, err := o.QueryTable(<span class="string">&quot;cardgroup&quot;</span>).Filter(<span class="string">&quot;Cards__Card__Name&quot;</span>, cardName).All(&amp;cardgroups)</span><br></pre></td></tr></table></figure><p>他指出“很多 ORM 都提供了这种 Filter 类型的查询方式，不过在某些 ORM 背后可能隐藏了非常难以察觉的细节，比如生成的 SQL 语句会自动 <code>limit 1000</code>”。这确实是一件很可怕的事情。</p><p>抛开上面的例子不谈，数据库操作本来就有其固有的复杂性。ORM 试图用面向对象的简单模型去映射关系型数据库的复杂世界，这种映射本身就可能引入歧义或意外的行为。</p><p>当遇到性能瓶颈、复杂查询或需要精确控制数据库行为时，ORM 又迫使开发者不得不去理解它试图隐藏的东西。这时，当初为了方便而引入的抽象，反而增加了认知负担和调试难度。</p><h2 id="辨析2-高级语言的抽象-vs-ORM"><a href="#辨析2-高级语言的抽象-vs-ORM" class="headerlink" title="辨析2: 高级语言的抽象 vs ORM"></a>辨析2: 高级语言的抽象 vs ORM</h2><p>高级语言隐藏的往往是机器底层的细节，比如寄存器、内存地址、指令集等。它们使得开发人员可以用心关注业务逻辑的实现而非程序在计算机上的运行方式。这种抽象是基础性的、安全的。编译器&#x2F;解释器只负责高效并且准确地将高级语言程序代码翻译成底层机器代码，这种翻译通常是可靠并且行为一致的。虽说大部分编译器会进行编译优化，但这并不会影响程序本身的语义。</p><p>反观 ORM，它是在一个已经存在的、成熟的、语义明确的领域（关系数据库）之上，叠加了另一层领域模型（对象模型）。这层抽象可不是基础性的，它更像是一个胶水层。它的目标是弥合两个不同范式的差异，但这种弥合本身就可能引入新的复杂性和不确定性。它的“翻译”（对象操作 -&gt; SQL）过程比高级语言编译要复杂得多，充满了各种配置选项和潜在的陷阱，其行为往往不如编译器那样确定和透明。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>经过一番思考后，我还是比较赞同该书作者的看法的。作者批评的并不是“隐藏细节”本身，而是过度地、不透明地隐藏那些对理解系统行为、性能和可维护性至关重要的细节。封装的隐藏是为了程序解耦和；高级语言的抽象是为了提供更为强大的基础能力。而 ORM 的过度抽象，其危险在于它让开发者在一个“方便”的幻象下工作，却可能在后台进行着复杂、低效甚至难以追踪的操作，最终导致系统变得像一个黑盒，难以理解、调试和优化，这正是作者担忧的“运行完全失控”和“面目全非，难以维护”的根源。<strong>好的抽象应该让复杂的事情变简单，而不是让简单的事情背后变得复杂且不可见。</strong></p><p><strong>但是</strong>🤓，让数据的操作和存储的具体实现相剥离这件事情我认为还是很有进步意义的，对于大部分 CURD项目，ORM 确实能极大地提升开发效率（比如大部分 ORM 都会有代码生成器，给它一个数据库地址，一行命令就能从 DAO 层生成到 Controller 层。真的牛逼）。我本身也是个 ORM 的重度使用者。</p><p>最后，用导师曾经说过的一句话作为文章结尾：</p><blockquote><p>你犯下的很多小错误在当下可能并不会显现出来，但在未来的某一刻它们极有可能会突然爆发，而且爆发的时候你还不知道问题出在哪。</p></blockquote>]]></content>
    
    
    <summary type="html">封装的隐藏建立清晰边界；高级语言抽象提供基础能力；而 ORM 的过度抽象可能制造“方便”的幻象，掩盖后台的复杂与低效，最终使系统变成难以掌控的黑盒</summary>
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="ORM" scheme="https://blog.pushihao.com/tags/ORM/"/>
    
    <category term="思考" scheme="https://blog.pushihao.com/tags/%E6%80%9D%E8%80%83/"/>
    
  </entry>
  
  <entry>
    <title>Git Merge VS Git Rebase: 如何优雅地合并分支？</title>
    <link href="https://blog.pushihao.com/article/7c1b7e45.html"/>
    <id>https://blog.pushihao.com/article/7c1b7e45.html</id>
    <published>2025-04-10T08:44:15.000Z</published>
    <updated>2025-04-13T06:03:10.000Z</updated>
    
    <content type="html"><![CDATA[<p>有关 Git 的常用基本操作，我在👉 <a href="https://blog.pushihao.com/article/2df4f2b8.html">Git 基本使用</a>这篇文章里已经介绍过了，这里不多赘述。我们今天主要讲讲 Git Merge 与 Git Rebase 的基础概念与使用场景。</p><h1 id="概念解释"><a href="#概念解释" class="headerlink" title="概念解释"></a>概念解释</h1><p>虽说两者都可以用来将一个分支（为了表达清晰我们暂且称之为待合并分支）合并到另一个分支（我们称之为目标分支或当前分支），但设计理念却是完全不同的。我们首先介绍两者的基本概念以及使用方法，在随后的使用场景中我们再来比较两者的区别。</p><h2 id="Git-Merge"><a href="#Git-Merge" class="headerlink" title="Git Merge"></a>Git Merge</h2><p>首先需要知道，Git Merge 有两种常见的合并方式。</p><p><strong>快进合并（Fast-forward merge）</strong></p><p>此合并方式发生的条件为目标分支自创建出待合并分支后没有任何提交。合并过程可以简单理解为目标分支将待合并分支的多出来的提交记录补到自己的后面，并移动自己的HEAD指针到最后一个提交记录。</p><p>特点：</p><ul><li>保留两个分支的提交记录，并且提交记录为<strong>线性</strong></li><li>最简单的一种情况，不会发生冲突</li><li>合并后的最后一次提交记录为待合并分支的提交，合并操作本身<strong>不会创建</strong>新的提交记录</li></ul><p>举个栗子，场景如下：Dabby 从 main 分支的提交 <code>Initial commit</code> 拉取了 dev 分支，然后依次进行了提交 <code>Add login</code> 和 <code>Fix bugs</code>。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131101244.png" alt="image-20250413110110202"></p><p>最后在 main 分支上执行 <code>git merge dev</code> 合并 dev 分支。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131103866.png" alt="image-20250413110315834"></p><p>执行 <code>git log --all --graph --oneline --decorate</code> 查看拓扑结构如下（合并后）：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504122116586.png" alt="image-20250412211625538"></p><p><strong>普通合并（Recursive merge）</strong></p><p>此合并方式发生的条件为目标分支自创建出待合并分支后目标分支和待合并分支都有提交。可以理解为是快进合并到升级版本。</p><p>特点：</p><ul><li>保留两个分支的提交记录</li><li>可能会发生<strong>冲突</strong></li><li>合并操作本身会创建一个新的合并提交记录</li></ul><p>举个🌰，场景如下：Dabby 从 main 分支的提交 <code>Initial commit</code> 拉取了 dev 分支，然后进行了提交 <code>Fix bugs</code>，与此同时，main 分支也创建了一个 <code>Update</code> 提交。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131105256.png" alt="image-20250413110517213"></p><p>最后在 main 分支上执行 <code>git merge dev -m &quot;Merge&quot;</code> 合并 dev 分支。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131113110.png" alt="image-20250413111324080"></p><p>执行 <code>git log --all --graph --oneline --decorate</code> 查看拓扑结构如下（合并后）：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504122111899.png" alt="image-20250412211135154"></p><p>除了知道这两种合并方式外，我们还要知道在合并过程中的冲突原因以及处理策略。</p><p>原因：当两个分支修改了同一文件的相同部分时，Git 无法自动合并，此时便会产生合并冲突。</p><p>解决步骤：</p><ol><li>运行 <code>git merge</code> 后遇到冲突</li><li>使用 <code>git status</code> 查看冲突文件</li><li>手动编辑冲突文件（文件中有 <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code>, <code>=======</code> 和 <code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code> 标记），删除冲突标记并保留想要的代码</li><li>使用 <code>git add &lt;文件名&gt;</code> 标记冲突已解决</li><li>继续合并：<code>git merge --continue</code></li><li>完成合并：<code>git commit</code></li></ol><p>如果不想合并了或者冲突无法解决，执行 <code>git merge --abort</code> 回到合并前的状态。</p><p>此外 <code>git merge</code> 命令本身还提供了一些常见的合并选项以及合并策略，我们这里简单介绍一下。</p><p><strong>高级合并选项</strong></p><p>使用方式为 <code>git merge [option] branch_name</code> 如 <code>git merge --ff-only dev</code>。</p><ul><li><code>--no-ff</code> 强制创建新的合并提交，即使合并可以通过快进合并完成</li><li><code>--ff-only</code> 仅允许快进合并，若无法快进则合并失败</li><li><code>--squash</code> 将待合并分支的多个提交压缩为单个新提交，不保留待合并分支的提交历史</li><li><code>--no-commit</code> 合并代码到目标分支的工作区但不提交，允许手动检查或调整</li></ul><p><strong>合并策略参数</strong></p><p>使用 <code>-s</code> 指定合并策略，不加 <code>-s</code> 参数时默认为 <code>recursive</code> 策略。大多数情况下用默认策略就足够了，使用方式如 <code>git merge -s recursive dev</code>。</p><p>常用合并策略有</p><ul><li><code>recursive</code> 基于递归三路合并算法，通过共同祖先、目标分支和待合并分支的提交进行三方合并，自动解决非冲突修改，冲突部分需手动处理</li><li><code>resolve</code> 简化版的三路合并，仅寻找一个共同祖先，避免递归合并虚拟节点，可能减少自动合并但增加冲突概率</li><li><code>octopus</code> 同时合并多个分支，如 <code>git merge -s octopus feature1 feature2 feature3</code></li><li><code>subtree</code> 将子目录作为独立仓库合并，适用于模块化项目或子仓库管理，如 <code>git merge -s subtree module-folder</code></li><li><code>ours</code> 完全保留当前分支内容，忽略待合并分支的所有修改（即使无冲突），仅记录待合并分支的提交历史</li></ul><p><strong>冲突解决策略</strong></p><p>使用 <code>-X</code> 参数指定冲突解决策略，不加 <code>-X</code> 参数时默认<strong>不会应用任何冲突解决策略</strong>。使用方式如 <code>git merge -X ours</code>。</p><p>常用的冲突解决策略有</p><ul><li><code>ours</code> 冲突时自动选择当前分支的代码，非冲突部分正常合并</li><li><code>theirs</code> 冲突时自动选择待合并分支的代码，非冲突部分正常合并</li><li><code>ignore-space-change</code> 忽略空格差异（如缩进或换行符），减少无意义冲突</li><li><code>patience</code> 优化差异比对算法，更关注代码结构而非逐行匹配，提高合并准确性</li></ul><p>综上，我们可以写出如下命令</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git merge --no-ff -s recursive -X patience dev -m &quot;Merge dev&quot;</span><br></pre></td></tr></table></figure><h2 id="Git-Rebase"><a href="#Git-Rebase" class="headerlink" title="Git Rebase"></a>Git Rebase</h2><p>Rebase（变基）本质上是将一系列提交从一个分支移动到另一个分支的顶端。<mark class="hl-label blue">注意：在变基操作中，"当前分支"通常为个人开发分支</mark>，如 <code>dev</code> 分支。细品接下来的 5 个步骤。</p><p>Git Rebase 都做了哪些事？</p><ol><li>Git 会先找到当前分支和待合并分支（如 main）的共同祖先提交，即<strong>分叉点</strong></li><li>然后提取当前分支上所有分叉点之后的提交记录（保存为补丁）</li><li>丢弃当前分支分叉点之后的提交记录（第 2 步的补丁还在）</li><li>在<strong>当前分支</strong>的顶端应用<strong>待合并分支</strong>分叉点之后的提交记录</li><li>在当前分支的顶端根据第 2 步的补丁创建一组<strong>全新的提交</strong></li></ol><p>还没明白？我们举个例子，场景如下：Dabby 从 main 分支的提交 <code>Initial commit</code> 拉取了 dev 分支，然后进行了提交 <code>C</code> 和 <code>D</code>。与此同时，main 分支也创建了一个 <code>A</code> 提交。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131010405.png" alt="image-20250413101041216"></p><p>最后在 dev 分支上执行 <code>git rebase main</code> 变基 main 分支。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131017333.png" alt="image-20250413101735284"></p><p>因为是纯线性历史，这里就不放拓扑图了。以下是提交记录的线性关系表示。</p><p>变基前</p><p>main: <code>Initial commit</code> -&gt; <code>A</code></p><p>dev: <code>Initial commit</code> -&gt; <code>C</code> -&gt; <code>D</code></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131035612.png" alt="image-20250413103522570"></p><p>变基后</p><p>main: <code>Initial commit</code> -&gt; <code>A</code></p><p>dev: <code>Initial commit</code> -&gt; <code>A</code> -&gt; <code>C&#39;</code> -&gt; <code>D&#39;</code></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202504131033244.png" alt="image-20250413103351206"></p><div class="note info no-icon flat"><p>可以看到，1.变基后并不会修改待合并分支(main)。 2.变基后自身(dev)的提交历史发生改变。3.如果想让修改合并到 main 分支则必须切换到 main 分支后执行一次 Fast-forward 合并。</p></div><p>变基遇到文件冲突后我们可以解决：</p><ol><li>运行 <code>git rebase main</code> 后遇到冲突</li><li>使用 <code>git status</code> 查看冲突文件</li><li>手动编辑冲突文件（文件中有 <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code>, <code>=======</code> 和 <code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code> 标记），删除冲突标记并保留想要的代码</li><li>使用 <code>git add &lt;文件名&gt;</code> 标记冲突已解决</li><li>执行 <code>git rebase --continue</code> 继续变基</li></ol><p>或者执行 <code>git rebase --abort</code> 取消变基。</p><p>有个有意思的事，<code>git rebase</code> 命令还有一个 <code>-i</code>&#x2F;<code>--interactive</code> 参数，可以开启交互式变基模式，允许用户编辑提交历史（如合并提交、修改提交信息、调整顺序等）。</p><h1 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h1><p>通过上面的学习，我们对 Git Merge 和 Git Rebase 的基础概念以及合并方式有了一个大致的了解，接下来我们需要了解他们的区别以及在各种场景下应该使用什么方式。</p><p>一张表格总结它们的核心区别：</p><table><thead><tr><th align="center">对比维度</th><th align="center">Git Merge</th><th align="center">Git Rebase</th></tr></thead><tbody><tr><td align="center">合并方式</td><td align="center">创建新的合并提交，保留两个分支的提交历史</td><td align="center">将当前分支的提交应用到待合并分支的最新提交后</td></tr><tr><td align="center">历史记录</td><td align="center">保留原始提交记录</td><td align="center">重写历史</td></tr><tr><td align="center">适用分支</td><td align="center">公共分支(如main)以及需要保留合并历史的分支</td><td align="center">个人开发分支或本地分支</td></tr><tr><td align="center">冲突处理</td><td align="center">合并提交时一次性解决冲突</td><td align="center">变基过程中逐个提交解决冲突（可能多次）</td></tr><tr><td align="center">是否线性</td><td align="center">不一定为线性</td><td align="center">一定为线性</td></tr><tr><td align="center">典型操作</td><td align="center"><code>git switch main</code> <code>git merge dev</code></td><td align="center"><code>git switch dev</code> <code>git rebase main</code></td></tr></tbody></table><p>综上所述：</p><ul><li>一般无特殊需求的情况下都用 <code>git merge</code> 是最稳妥的选择。</li><li>多人协作下的公共分支（如 main 分支）<strong>必须</strong>用 <code>git merge</code>。<strong>千万不要</strong>在公共分支上执行变基操作。</li><li>个人项目或者本地项目想用啥用啥。</li></ul><p>优雅，实在是优雅。</p>]]></content>
    
    
    <summary type="html">相比于直接在main分支上提交，分支开发有并行开发、保护主分支稳定性等优点。合并问题应运而生...</summary>
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="团队协作" scheme="https://blog.pushihao.com/tags/%E5%9B%A2%E9%98%9F%E5%8D%8F%E4%BD%9C/"/>
    
    <category term="Git" scheme="https://blog.pushihao.com/tags/Git/"/>
    
  </entry>
  
  <entry>
    <title>修改Linux内核模块以支持WG</title>
    <link href="https://blog.pushihao.com/article/9405f871.html"/>
    <id>https://blog.pushihao.com/article/9405f871.html</id>
    <published>2024-12-31T01:12:02.000Z</published>
    <updated>2024-12-31T01:12:02.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>我的服务器系统是OpenCloudOS 9.2，内核为6.6.34-9.oc9.x86_64。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412310937117.png" alt="image-20241231093722024"></p><p>我想在服务器上使用Wireguard，按理说5.6之后的Linux内核应该是内建该模块的，但是该系统中并没有。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412310941328.png" alt="image-20241231094103286"></p><p>于是通过重新编译内核的方式来启用Wireguard的支持。</p><h1 id="编译安装内核"><a href="#编译安装内核" class="headerlink" title="编译安装内核"></a>编译安装内核</h1><h2 id="内核源码位置"><a href="#内核源码位置" class="headerlink" title="内核源码位置"></a>内核源码位置</h2><p>可以使用原本的内核源码：&#x2F;usr&#x2F;src&#x2F;kernels</p><p>下载新内核源码：<a href="https://www.kernel.org/">https://www.kernel.org/</a></p><p>如6.12.7的源码包：<a href="https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.12.7.tar.gz">https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.12.7.tar.gz</a></p><h2 id="安装相应工具包"><a href="#安装相应工具包" class="headerlink" title="安装相应工具包"></a>安装相应工具包</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">dnf groupinstall -y <span class="string">&quot;Development Tools&quot;</span></span><br><span class="line">dnf install -y gcc make ncurses-devel bison flex elfutils-libelf-devel openssl-devel bc perl</span><br><span class="line">dnf install -y kernel-devel-$(<span class="built_in">uname</span> -r) kernel-headers-$(<span class="built_in">uname</span> -r)</span><br><span class="line">dnf install -y pkgconfig libmnl-devel</span><br></pre></td></tr></table></figure><h2 id="配置内核模块"><a href="#配置内核模块" class="headerlink" title="配置内核模块"></a>配置内核模块</h2><ol><li>进入内核源码所在的文件夹，首先复制原内核的配置项</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp /boot/config-$(uname -r) .config</span><br></pre></td></tr></table></figure><ol start="2"><li>允许Wireguard内核</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make menuconfig</span><br></pre></td></tr></table></figure><p>输入命令后会进入一个配置菜单，Wireguard配置项在<code>Device Drivers --&gt; Network device support --&gt; WireGuard secure network tunnel</code>，输入<code>M</code>(module)或<code>Y</code>(built-in)，也可以开启其后的<code>Debugging checks and verbose messages</code>(输入<code>Y</code>)。</p><p>其他模块同理，把自己想要的配置都配置完成后通过光标先<code>Save</code>再<code>Exit</code>即可。</p><p>通过grep命令查看模块是否被正确修改</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep WIREGUARD .config</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412311007819.png"></p><h2 id="编译安装内核-1"><a href="#编译安装内核-1" class="headerlink" title="编译安装内核"></a>编译安装内核</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 若之前编译过，先清理一下</span><br><span class="line">make clean</span><br><span class="line">make mrproper</span><br><span class="line"></span><br><span class="line"># -j表示使用多个CPU核心进行编译，提高速度</span><br><span class="line">make -j$(nproc)</span><br><span class="line">make modules_install</span><br><span class="line">make install</span><br></pre></td></tr></table></figure><p>这步会比较慢，耐心等待即可。</p><h2 id="更新引导程序"><a href="#更新引导程序" class="headerlink" title="更新引导程序"></a>更新引导程序</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">grub2-mkconfig -o /boot/grub2/grub.cfg</span><br><span class="line">reboot</span><br></pre></td></tr></table></figure><p>重启后可以检查内核是否被成功安装</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">uname</span> -r</span><br></pre></td></tr></table></figure><h1 id="检测WireGuard模块"><a href="#检测WireGuard模块" class="headerlink" title="检测WireGuard模块"></a>检测WireGuard模块</h1><p>检测wireguard模块是否被包含在内核中</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> /lib/modules/$(<span class="built_in">uname</span> -r)/kernel/drivers/net/wireguard/</span><br></pre></td></tr></table></figure><p>加载该模块</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">modprobe wireguard</span><br></pre></td></tr></table></figure><p>检测模块是否被加载</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsmod | grep wireguard</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412311421424.png" alt="image-20241231141523880"></p><p>完成！</p>]]></content>
    
    
    <summary type="html">Linux通过编译安装内核的方式来使用原本内核没有启动的模块，如WireGuard</summary>
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Linux" scheme="https://blog.pushihao.com/tags/Linux/"/>
    
    <category term="内核" scheme="https://blog.pushihao.com/tags/%E5%86%85%E6%A0%B8/"/>
    
    <category term="Wireguard" scheme="https://blog.pushihao.com/tags/Wireguard/"/>
    
  </entry>
  
  <entry>
    <title>OpenLDAP折腾日记</title>
    <link href="https://blog.pushihao.com/article/9c14209c.html"/>
    <id>https://blog.pushihao.com/article/9c14209c.html</id>
    <published>2024-12-12T03:42:21.000Z</published>
    <updated>2025-08-02T03:06:51.000Z</updated>
    
    <content type="html"><![CDATA[<p>折腾了几天OpenLDAP，终于是把它给部署上了。对于软件部署这件事，我的评价是不要完全相信网上任何一篇几年前的教程（包括这篇），可能一些操作是对的，但另一些操作已经过时了，这会导致一些莫名奇妙的错误。配置文件中配置项上一般会有注释，看懂了再改。</p><h1 id="OpenLDAP服务端部署"><a href="#OpenLDAP服务端部署" class="headerlink" title="OpenLDAP服务端部署"></a>OpenLDAP服务端部署</h1><blockquote><p>Linux：RockyLinux9</p></blockquote><h2 id="安装相关软件"><a href="#安装相关软件" class="headerlink" title="安装相关软件"></a>安装相关软件</h2><p>这步没啥说的，照着安装就行了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm</span><br><span class="line">dnf upgrade -y</span><br><span class="line">dnf install -y openldap openldap-servers openldap-clients nginx phpldapadmin</span><br></pre></td></tr></table></figure><p>安装后直接启动，不用顾虑</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start slapd</span><br></pre></td></tr></table></figure><h2 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h2><p>首先查看自己的配置文件命令，这很重要。执行<code>ls /etc/openldap/slapd.d/cn\=config/</code></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412140955051.png" alt="image-20241214095534004"></p><p>然后生成密码，执行命令 <code>slappasswd -s your_password</code>，这会在下面生成一个加密后的密码，如{SSHA}+TszwnXVhnhH5HFGK5Nf4A0xZWGHrmRN，把这个记录下来。</p><p>创建以下三个文件</p><p>init.ldif</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">dn: olcDatabase=&#123;2&#125;mdb,cn=config</span><br><span class="line">changetype: modify</span><br><span class="line">replace: olcRootDN</span><br><span class="line">olcRootDN: cn=admin,dc=pushihao,dc=com</span><br><span class="line">-</span><br><span class="line">replace: olcSuffix</span><br><span class="line">olcSuffix: dc=pushihao,dc=com</span><br><span class="line">-</span><br><span class="line">replace: olcRootPW</span><br><span class="line">olcRootPW: &#123;SSHA&#125;+TszwnXVhnhH5HFGK5Nf4A0xZWGHrmRN</span><br></pre></td></tr></table></figure><p>access.ldif</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">dn: olcDatabase=&#123;1&#125;monitor,cn=config</span><br><span class="line">changetype: modify</span><br><span class="line">replace: olcAccess</span><br><span class="line">olcAccess: &#123;0&#125;to * by dn.base=&quot;gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth&quot; read by dn.base=&quot;cn=admin,dc=pushihao,dc=com&quot; read by * none</span><br></pre></td></tr></table></figure><p>base.ldif</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></pre></td><td class="code"><pre><span class="line">dn: dc=pushihao,dc=com</span><br><span class="line">o: PSH Organization</span><br><span class="line">dc: pushihao</span><br><span class="line">objectClass: top</span><br><span class="line">objectClass: dcObject</span><br><span class="line">objectclass: organization</span><br><span class="line"></span><br><span class="line">dn: cn=admin,dc=pushihao,dc=com</span><br><span class="line">cn: admin</span><br><span class="line">objectClass: organizationalRole</span><br><span class="line">description: Directory Manager</span><br></pre></td></tr></table></figure><p>文件解读（前两个文件）：第一行的dn指定了要修改的条目的唯一标识符，根据刚刚查看的名称来。changetype指定了对条目的修改类型。replace指定了要修改的字段名称，其接下来的一行表示修改后的值。记得把olcRootPW字段替换为刚刚生成的密码。</p><p>文件解读（第三个文件）：第一段新建一个域，第二段新建了一个管理员。</p><p>文件创建好之后执行文件进行修改</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ldapadd -Q -Y EXTERNAL -H ldapi:/// -f init.ldif</span><br><span class="line">ldapadd -Q -Y EXTERNAL -H ldapi:/// -f access.ldif</span><br><span class="line">ldapadd -x -D &#x27;cn=admin,dc=pushihao,dc=com&#x27; -w &#x27;your_password&#x27; -f base.ldif</span><br></pre></td></tr></table></figure><p>导入基本的Schema</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">ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif</span><br><span class="line">ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif</span><br><span class="line">ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif</span><br></pre></td></tr></table></figure><h2 id="使用PHPLDAPAdmin管理OpenLDAP"><a href="#使用PHPLDAPAdmin管理OpenLDAP" class="headerlink" title="使用PHPLDAPAdmin管理OpenLDAP"></a>使用PHPLDAPAdmin管理OpenLDAP</h2><p>修改&#x2F;etc&#x2F;phpldapadmin&#x2F;config.php</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">$servers-&gt;setValue(&#x27;login&#x27;,&#x27;attr&#x27;,&#x27;dn&#x27;);</span><br><span class="line">$servers-&gt;setValue(&#x27;login&#x27;,&#x27;anon_bind&#x27;,false);</span><br><span class="line">$servers-&gt;setValue(&#x27;login&#x27;,&#x27;allowed_dns&#x27;,array(&#x27;cn=admin,dc=pushihao,dc=com&#x27;));</span><br></pre></td></tr></table></figure><p>修改解读：第一行表示使用完整的dn作为登录凭据，第二行表示不允许匿名访问，第三行表示仅允许指定的dn进行登录</p><p>修改&#x2F;etc&#x2F;nginx&#x2F;nginx.conf，添加一个server</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></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen 8080;</span><br><span class="line"></span><br><span class="line">    root /usr/share/phpldapadmin/htdocs;</span><br><span class="line">    index index.php;</span><br><span class="line"></span><br><span class="line">    location / &#123;</span><br><span class="line">        try_files $uri $uri/ =404;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    location ~ \.php$ &#123;</span><br><span class="line">        include fastcgi_params;</span><br><span class="line">        fastcgi_pass unix:/run/php-fpm/www.sock;</span><br><span class="line">        fastcgi_param SCRIPT_FILENAME /usr/share/phpldapadmin/htdocs$fastcgi_script_name;</span><br><span class="line">        include fastcgi_params;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    location ~ /\.ht &#123;</span><br><span class="line">        deny all;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意fastcgi_pass这个配置项：查看<code>/etc/php-fpm.d/www.conf</code>这个文件，把fastcgi_pass这个配置项和<code>/etc/php-fpm.d/www.conf</code>文件中的listen配置项保持一致（它监听9000端口你也监听，它若用套接字你也用套接字）。</p><p>配置完成后重启nginx<code>nginx -s reload</code>即可在浏览器输入ip:8080访问PHPLDAPAdmin的web界面，用户名为cn&#x3D;admin,dc&#x3D;pushihao,dc&#x3D;com，密码为最开始设置的密码（输入未加密的）。</p><h1 id="OpenLDAP-SSH客户端部署"><a href="#OpenLDAP-SSH客户端部署" class="headerlink" title="OpenLDAP SSH客户端部署"></a>OpenLDAP SSH客户端部署</h1><p>服务端起来之后就可以根据需求配置各种各样支持ldap的客户端了，ssh是一个常见的需求。这里使用轻量级的nslcd工具。</p><h2 id="安装相关软件-1"><a href="#安装相关软件-1" class="headerlink" title="安装相关软件"></a>安装相关软件</h2><p>没啥说的，装就完了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm</span><br><span class="line">dnf upgrade -y</span><br><span class="line">dnf install -y openldap-clients nss-pam-ldapd</span><br></pre></td></tr></table></figure><h2 id="配置nslcd"><a href="#配置nslcd" class="headerlink" title="配置nslcd"></a>配置nslcd</h2><p>修改配置文件&#x2F;etc&#x2F;nslcd.conf，参考以下内容，如果之前的配置跟我不同（如密码），则灵活修改</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">uid root</span><br><span class="line">gid root</span><br><span class="line"></span><br><span class="line">uri ldap://ldap-node-01/</span><br><span class="line">base dc=pushihao,dc=com</span><br><span class="line"></span><br><span class="line">binddn cn=admin,dc=pushihao,dc=com</span><br><span class="line">bindpw root</span><br><span class="line">ssl no</span><br></pre></td></tr></table></figure><p>修改配置文件&#x2F;etc&#x2F;nsswitch.conf，参考以下内容，灵活修改</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">passwd:     files ldap sss systemd</span><br><span class="line">shadow:     files ldap</span><br><span class="line">group:      files ldap sss systemd</span><br><span class="line">hosts:      files dns myhostname</span><br><span class="line">services:   files ldap sss</span><br><span class="line">netgroup:   files ldap sss</span><br><span class="line">automount:  files ldap sss</span><br><span class="line"></span><br><span class="line">aliases:    files</span><br><span class="line">ethers:     files</span><br><span class="line">gshadow:    files</span><br><span class="line">networks:   files dns</span><br><span class="line">protocols:  files</span><br><span class="line">publickey:  files</span><br><span class="line">rpc:        files</span><br></pre></td></tr></table></figure><h2 id="配置pam"><a href="#配置pam" class="headerlink" title="配置pam"></a>配置pam</h2><p>修改&#x2F;etc&#x2F;pam.d&#x2F;password-auth</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">#%PAM-1.0</span><br><span class="line"># This file is auto-generated.</span><br><span class="line"># User changes will be destroyed the next time authselect is run.</span><br><span class="line">auth        required      pam_env.so</span><br><span class="line">auth        sufficient    pam_unix.so try_first_pass nullok</span><br><span class="line">auth        sufficient    pam_ldap.so use_first_pass                      # 这里</span><br><span class="line">auth        required      pam_deny.so</span><br><span class="line"></span><br><span class="line">account     required      pam_unix.so</span><br><span class="line">account     [default=bad success=ok user_unknown=ignore] pam_ldap.so      # 这里</span><br><span class="line"></span><br><span class="line">password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=</span><br><span class="line">password    sufficient    pam_unix.so try_first_pass use_authtok nullok sha512 shadow</span><br><span class="line">password    sufficient    pam_ldap.so use_authtok                         # 这里</span><br><span class="line">password    required      pam_deny.so</span><br><span class="line"></span><br><span class="line">session     optional      pam_keyinit.so revoke</span><br><span class="line">session     required      pam_limits.so</span><br><span class="line">-session     optional      pam_systemd.so</span><br><span class="line">session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid</span><br><span class="line">session     required      pam_unix.so</span><br><span class="line">session     optional      pam_ldap.so                                     # 这里</span><br></pre></td></tr></table></figure><p>修改&#x2F;etc&#x2F;pam.d&#x2F;system-auth</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">#%PAM-1.0</span><br><span class="line"># This file is auto-generated.</span><br><span class="line"># User changes will be destroyed the next time authselect is run.</span><br><span class="line">auth        required      pam_env.so</span><br><span class="line">auth        sufficient    pam_unix.so try_first_pass nullok</span><br><span class="line">auth        sufficient    pam_ldap.so use_first_pass                      # 这里</span><br><span class="line">auth        required      pam_deny.so</span><br><span class="line"></span><br><span class="line">account     required      pam_unix.so</span><br><span class="line">account     [default=bad success=ok user_unknown=ignore] pam_ldap.so      # 这里</span><br><span class="line"></span><br><span class="line">password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=</span><br><span class="line">password    sufficient    pam_unix.so try_first_pass use_authtok nullok sha512 shadow</span><br><span class="line">password    sufficient    pam_ldap.so use_authtok                         # 这里</span><br><span class="line">password    required      pam_deny.so</span><br><span class="line"></span><br><span class="line">session     optional      pam_keyinit.so revoke</span><br><span class="line">session     required      pam_limits.so</span><br><span class="line">-session     optional      pam_systemd.so</span><br><span class="line">session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid</span><br><span class="line">session     required      pam_unix.so</span><br><span class="line">session     optional      pam_ldap.so                                     # 这里</span><br></pre></td></tr></table></figure><p>修改&#x2F;etc&#x2F;ssh&#x2F;sshd_config</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">PasswordAuthentication yes</span><br><span class="line">UsePAM yes</span><br></pre></td></tr></table></figure><h2 id="重启相关软件"><a href="#重启相关软件" class="headerlink" title="重启相关软件"></a>重启相关软件</h2><p>全部配置文件修改完成之后重启相关软件即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart sshd nslcd</span><br></pre></td></tr></table></figure><p>然后就可以使用在ldap系统中新建的用户通过ssh连接到服务器了。</p><p>搞定！</p><hr><p>2025.08.02 更新</p><h2 id="使用-ldap-管理管理员用户"><a href="#使用-ldap-管理管理员用户" class="headerlink" title="使用 ldap 管理管理员用户"></a>使用 ldap 管理管理员用户</h2><p>今天突然发现了一个问题，经过以上一通操作后。将用户添加到 wheel 组后仍然没有拥有管理员权限。</p><p>去看了一眼 sudoers 文件，发现 wheel 组确实是在里面的，并且没有被注释掉。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202508021056477.png" alt="image-20250802105625430"></p><p>于是查看 super 用户的 uid、gid 等信息，发现了一件有点令人匪夷所思的事情，明明使用 id 命令查看 super 用户是在 wheel 组的，但是 getent 命令却查不到。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202508021052813.png" alt="image-20250802105207266"></p><p>多次试验后我还是找到了问题所在：nsswitch.conf 的机制。</p><p>可以翻到上面看到我们配置的该文件有一行：<code>group: files ldap sss systemd</code>，也就是说如果在本地文件 (&#x2F;etc&#x2F;group) 找到了一个用户组，那就不会再往后面查找了。而 wheel 用户组又是 RockyLinux 系统默认就存在的组，所以 OpenLDAP 远程的 wheel 组会被覆盖掉。</p><p>问题找到了，那么解决方案就很清晰了。</p><ul><li>解决方案1: 注释掉 &#x2F;etc&#x2F;group 中 <code>wheel:x:10:</code> 这一行。</li><li>解决方案2: 修改 &#x2F;etc&#x2F;nsswitch.conf 中 group 的配置，将 ldap 提到 files 前面，即 <code>group: ldap files sss systemd</code>。</li></ul><p>这下才是真的搞定！</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Linux" scheme="https://blog.pushihao.com/tags/Linux/"/>
    
    <category term="OpenLDAP" scheme="https://blog.pushihao.com/tags/OpenLDAP/"/>
    
  </entry>
  
  <entry>
    <title>非特权模式容器 ssh 登录问题</title>
    <link href="https://blog.pushihao.com/article/29ce0a20.html"/>
    <id>https://blog.pushihao.com/article/29ce0a20.html</id>
    <published>2024-12-09T02:53:03.000Z</published>
    <updated>2024-12-14T01:05:03.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一、问题描述"><a href="#一、问题描述" class="headerlink" title="一、问题描述"></a>一、问题描述</h2><p>使用 podman 运行一个以 systemd 模式启动的容器，并且没有赋予 privileged 权限。sshd 正常启动，sshd_config 正常设置，但是使用 ssh 远程登录时出现：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412091122611.png" alt="image-20241209112228498"></p><p>（非 root 用户也是如此）</p><h2 id="二、查看原因"><a href="#二、查看原因" class="headerlink" title="二、查看原因"></a>二、查看原因</h2><p>查看 &#x2F;var&#x2F;log&#x2F;secure 文件，发现文件内容为空</p><p>使用 journalctl -u sshd 命令查看错误日志如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202412091127685.png" alt="image-20241209112707630"></p><p>分析错误原因：</p><ul><li>权限不足，无法将 uid 写入 &#x2F;proc&#x2F;self&#x2F;loginuid 文件中</li><li>sshd 进程无法与 system 总线通信</li></ul><h2 id="三、解决"><a href="#三、解决" class="headerlink" title="三、解决"></a>三、解决</h2><p>最佳方案：给予容器更多的权限</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">- AUDIT_WRITE</span><br><span class="line">- SYS_RAWIO</span><br><span class="line">- AUDIT_CONTROL</span><br></pre></td></tr></table></figure><p>方案二：删除这些报错相关的 pam</p><p>&#x2F;etc&#x2F;pam.d&#x2F;sshd</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">#session    required     pam_loginuid.so</span><br></pre></td></tr></table></figure><p>&#x2F;etc&#x2F;pam.d&#x2F;system-auth 和 &#x2F;etc&#x2F;pam.d&#x2F;password-auth</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">#-session    optional    pam_systemd.so</span><br></pre></td></tr></table></figure><p>方案三：以特权模式运行容器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">--privileged</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">pam_loginuid(sshd:session): Error writing /proc/self/loginuid: Operation not permitted</summary>
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Linux" scheme="https://blog.pushihao.com/tags/Linux/"/>
    
    <category term="容器" scheme="https://blog.pushihao.com/tags/%E5%AE%B9%E5%99%A8/"/>
    
    <category term="Podman" scheme="https://blog.pushihao.com/tags/Podman/"/>
    
    <category term="SSH" scheme="https://blog.pushihao.com/tags/SSH/"/>
    
  </entry>
  
  <entry>
    <title>在 Linux 开发环境中使用网络代理</title>
    <link href="https://blog.pushihao.com/article/d5d088c3.html"/>
    <id>https://blog.pushihao.com/article/d5d088c3.html</id>
    <published>2024-10-17T03:33:56.000Z</published>
    <updated>2025-05-25T05:36:58.000Z</updated>
    
    <content type="html"><![CDATA[<p>默认现在本机已经安装好了代理软件客户端，暴露出的 http 端口为7890，socks5 端口为7891。</p><span class="hide-inline"><button type="button" class="hide-button" style="background-color:  green;color:  white"> 为什么要这样默认？</button><span class="hide-content">因为此域名是接受过国内备案的，不易多说 🤫</span></span><h2 id="Linux-Shell使用网络代理"><a href="#Linux-Shell使用网络代理" class="headerlink" title="Linux Shell使用网络代理"></a>Linux Shell使用网络代理</h2><h3 id="当前终端使用代理"><a href="#当前终端使用代理" class="headerlink" title="当前终端使用代理"></a>当前终端使用代理</h3><p>设置代理：<code>export http_proxy=http://127.0.0.1:7890 &amp;&amp; export https_proxy=http://127.0.0.1:7890</code></p><p>取消代理：<code>unset http_proxy &amp;&amp; unset https_proxy</code></p><h3 id="全局使用代理"><a href="#全局使用代理" class="headerlink" title="全局使用代理"></a>全局使用代理</h3><p>如果是root用户，修改&#x2F;etc&#x2F;profile。如果是普通用户，修改~&#x2F;.bashrc。在文件最后添加如下内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># &gt;&gt;&gt; proxy settings &gt;&gt;&gt;</span></span><br><span class="line"><span class="built_in">export</span> https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7891</span><br><span class="line"><span class="comment"># &gt;&gt;&gt; proxy settings &gt;&gt;&gt;</span></span><br></pre></td></tr></table></figure><p>然后刷新配置文件：<code>source /etc/profile</code>或者<code>source ~/.bashrc</code></p><h2 id="Docker使用网络代理"><a href="#Docker使用网络代理" class="headerlink" title="Docker使用网络代理"></a>Docker使用网络代理</h2><h3 id="Docker本身使用代理-如docker-pull"><a href="#Docker本身使用代理-如docker-pull" class="headerlink" title="Docker本身使用代理(如docker pull)"></a>Docker本身使用代理(如docker pull)</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /etc/systemd/system/docker.service.d</span><br></pre></td></tr></table></figure><p>添加代理</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/systemd/system/docker.service.d/http-proxy.conf</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[Service]</span><br><span class="line">Environment=&quot;HTTP_PROXY=http://127.0.0.1:7890&quot;</span><br><span class="line">Environment=&quot;HTTPS_PROXY=http://127.0.0.1:7890&quot;</span><br></pre></td></tr></table></figure><p>重启docker</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">systemctl daemon-reload</span><br><span class="line">systemctl restart docker</span><br></pre></td></tr></table></figure><h3 id="Docker容器使用代理"><a href="#Docker容器使用代理" class="headerlink" title="Docker容器使用代理"></a>Docker容器使用代理</h3><ol><li>如果是在Dockerfile中，则直接设置</li></ol><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ENV</span> http_proxy=<span class="string">&#x27;http://127.0.0.1:7890&#x27;</span></span><br><span class="line"><span class="keyword">ENV</span> https_proxy=<span class="string">&#x27;http://127.0.0.1:7890&#x27;</span></span><br></pre></td></tr></table></figure><ol start="2"><li>如果是在docker run时想添加代理，则使用<code>-e</code>进行添加，如</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d -e http_proxy=http://127.0.0.1:7890 -e https_proxy=http://127.0.0.1:7890 image</span><br></pre></td></tr></table></figure><h2 id="Git使用网络代理"><a href="#Git使用网络代理" class="headerlink" title="Git使用网络代理"></a>Git使用网络代理</h2><p>如果已经用上述 “Linux Shell使用网络代理” 配置过了，则 git 会默认使用上面配置的。如果只想单独给 git 配置代理，参考下面的方法。</p><ol><li>方法一：编辑文件</li></ol><p>编辑文件<code>~/.gitconfig</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim ~/.gitconfig</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[https]</span><br><span class="line">proxy = http://127.0.0.1:7890</span><br><span class="line">[http]</span><br><span class="line">proxy = http://127.0.0.1:7890</span><br></pre></td></tr></table></figure><ol start="2"><li>方法二：命令行</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置Git全局代理</span></span><br><span class="line">git config --global http.proxy http://127.0.0.1:7890</span><br><span class="line">git config --global https.proxy http://127.0.0.1:7890</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">git config --global http.http://github.com.proxy socks5://127.0.0.1:7891</span><br><span class="line">git config --global https.https://github.com.proxy socks5://127.0.0.1:7891</span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅针对Github网站设置代理</span></span><br><span class="line">git config --global http.http://github.com.proxy http://127.0.0.1:7890</span><br><span class="line">git config --global https.https://github.com.proxy http://127.0.0.1:7890</span><br><span class="line"></span><br><span class="line"><span class="comment"># 取消代理</span></span><br><span class="line">git config --global --<span class="built_in">unset</span> http.proxy</span><br><span class="line">git config --global --<span class="built_in">unset</span> https.proxy</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">开发环境所需的各种包往往都需要从国外网站下载，使用网络代理可以大大加快访问速度以及稳定性</summary>
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="网络代理" scheme="https://blog.pushihao.com/tags/%E7%BD%91%E7%BB%9C%E4%BB%A3%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>白嫖 Aseprite 像素绘图软件</title>
    <link href="https://blog.pushihao.com/article/467e816.html"/>
    <id>https://blog.pushihao.com/article/467e816.html</id>
    <published>2022-11-21T09:14:35.000Z</published>
    <updated>2025-08-02T01:11:52.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>白嫖的原理是通过构建他在 Github 上开源出来的源代码，绝对官方正版。</p></blockquote><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>听说 <a href="https://www.aseprite.org/">Aseprite</a> 是一款非常不错的像素绘图软件，最近闲的没事，想试一下。</p><p>但是一看，官网售价 19.99 USD，Steam 售价 70 RMB，实在是囊中羞涩，心有余而力不足。一看 Github，原来这个玩意儿是开源的，由 C++ 语言编写。</p><p>既然他是开源的，那我们就可以通过源代码自己编译出此软件。</p><p>当然，安装过程也可以查看<a href="https://github.com/aseprite/aseprite/blob/main/INSTALL.md">官方给出的文档</a>，看官方文档最大的好处就是不用担心时效性而且绝对准确</p><h2 id="Windows-编译安装"><a href="#Windows-编译安装" class="headerlink" title="Windows 编译安装"></a>Windows 编译安装</h2><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><ol><li>安装 Visual Studio 2022 并且记住安装位置<ol><li>下载链接：<a href="https://visualstudio.microsoft.com/zh-hans/downloads/">https://visualstudio.microsoft.com/zh-hans/downloads/</a></li></ol></li><li>安装 Ninja 并配置进 Path 环境变量<ol><li>下载链接：<a href="https://github.com/ninja-build/ninja/releases">https://github.com/ninja-build/ninja/releases</a></li></ol></li><li>安装 Skia<ol><li>下载链接：<a href="https://github.com/aseprite/skia/releases">Releases · aseprite&#x2F;skia · GitHub</a></li><li>将解压出来的文件放到 C:\deps\skia 目录下</li></ol></li><li>安装 Cmake 并配置进 Path 环境变量<ol><li>下载链接：<a href="https://cmake.org/download/">https://cmake.org/download/</a></li></ol></li><li>安装 Git<ol><li>下载链接：<a href="https://git-scm.com/download/win">Git - Downloading Package (git-scm.com)</a></li></ol></li><li>一台可以访问 Github 的电脑</li></ol><br><h3 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h3><ol><li>首先在一个没有中文的路径下下载源码</li></ol><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone <span class="literal">--recursive</span> https://github.com/aseprite/aseprite.git</span><br></pre></td></tr></table></figure><p>结果如下表示下载成功：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211211745082.png" alt="image-20221121174454999"></p><br><ol start="2"><li>执行命令</li></ol><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">call <span class="string">&quot;D:\SoftWare\VisualStudio2022\IDE\Common7\Tools\VsDevCmd.bat&quot;</span> <span class="literal">-arch</span>=x64  <span class="comment"># 注意：你的路径未必和我的一样</span></span><br></pre></td></tr></table></figure><p>结果如下表示成功：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211211752100.png" alt="image-20221121175209066"></p><br><ol start="3"><li>进入刚刚下载的 aseprite 文件夹</li><li>在 aseprite 文件夹下创建 build 文件夹</li><li>进入 build 文件夹</li><li>执行命令</li></ol><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cmake <span class="literal">-DCMAKE_BUILD_TYPE</span>=RelWithDebInfo <span class="literal">-DLAF_BACKEND</span>=skia <span class="literal">-DSKIA_DIR</span>=C:\deps\skia <span class="literal">-DSKIA_LIBRARY_DIR</span>=C:\deps\skia\out\Release<span class="literal">-x64</span> <span class="literal">-DSKIA_LIBRARY</span>=C:\deps\skia\out\Release<span class="literal">-x64</span>\skia.lib <span class="literal">-G</span> Ninja ..</span><br></pre></td></tr></table></figure><p>结果<strong>类似于</strong>下面表示成功：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211211800985.png" alt="image-20221121180042942"></p><br><ol start="7"><li>执行命令</li></ol><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ninja aseprite</span><br></pre></td></tr></table></figure><p>结果<strong>类似于</strong>下面表示成功：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211211758336.png" alt="image-20221121175847307"></p><br><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>上述命令全部执行成功后会在本目录下生成一个 bin 文件夹，这就是这个我们构建出来的软件目录。打开后会发现里面有一个 aseprite.exe 文件，就是他。</p><p>构建成功后，除此 bin 文件夹外，其他所有文件&#x2F;文件夹均可删除。</p><p>使用愉快😁😁</p><hr><p>2025.08.02 更新</p><h2 id="使用-Github-Actions-编译"><a href="#使用-Github-Actions-编译" class="headerlink" title="使用 Github Actions 编译"></a>使用 Github Actions 编译</h2><p>最近换了电脑，需要重新安装这个软件。正好前段时间刚学会使用 <a href="https://docs.github.com/en/actions">Github Actions</a>，想到使用这个会不会更方便点，一搜，还真有现成的 Actions YAML。那正好，直接拿来用。这里放个大佬写的目前能用的，就不重复造轮子了。</p><p><a href="https://github.com/a1393323447/aseprite-builder">https://github.com/a1393323447/aseprite-builder</a></p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="技术杂谈" scheme="https://blog.pushihao.com/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/"/>
    
    
    <category term="Aseprite" scheme="https://blog.pushihao.com/tags/Aseprite/"/>
    
    <category term="像素" scheme="https://blog.pushihao.com/tags/%E5%83%8F%E7%B4%A0/"/>
    
  </entry>
  
  <entry>
    <title>MongoDB 增删改查</title>
    <link href="https://blog.pushihao.com/article/85011f23.html"/>
    <id>https://blog.pushihao.com/article/85011f23.html</id>
    <published>2022-11-19T14:46:00.000Z</published>
    <updated>2022-11-19T14:46:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="数据库操作"><a href="#数据库操作" class="headerlink" title="数据库操作"></a>数据库操作</h2><p>查看所有数据库：show dbs;</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051059579.png" alt="image-20221105105938537"></p><br><p>切换数据库：use xxx;</p><p>没有xxx时会自动创建</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051057295.png" alt="image-20221105105703199"></p><br><p>新建集合（对应MySQL表）：db.createCollection(‘xxx’);</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051058859.png" alt="image-20221105105823823"></p><h2 id="常用文档操作命令（增删改查）"><a href="#常用文档操作命令（增删改查）" class="headerlink" title="常用文档操作命令（增删改查）"></a>常用文档操作命令（增删改查）</h2><h3 id="增"><a href="#增" class="headerlink" title="增"></a>增</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">db.collection.insertOne(</span><br><span class="line">&lt;document&gt;,</span><br><span class="line">&#123;</span><br><span class="line">writeConcern: &lt;document&gt;</span><br><span class="line">&#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">db.collection.insertMany(</span><br><span class="line">&lt;document&gt;,</span><br><span class="line">&#123;</span><br><span class="line">writeConcern: &lt;document&gt;</span><br><span class="line">&#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051103546.png" alt="image-20221105110341503"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051106356.png" alt="image-20221105110602314"></p><br><h3 id="删"><a href="#删" class="headerlink" title="删"></a>删</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">db.emp.deleteMany(&#123;&#125;)    //删除所有文档</span><br><span class="line">db.emp.deleteMany(&#123;name: &#x27;pillage&#x27;&#125;)    //删除所有name=pillage的文档</span><br><span class="line">db.emp.deleteMany(&#123;age: &#123;$gt: 20&#125;&#125;)     //删除所有age&gt;20的文档</span><br><span class="line">db.emp.deleteOne(&#123;name: &#x27;pillage&#x27;&#125;)     //删除name=pillage的第一个文档</span><br><span class="line"></span><br><span class="line">db.emp.findOneAndDelete(&#123;xxx&#125;)          //返回这个文档然后删除</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051113794.png" alt="image-20221105111347749"></p><br><h3 id="改"><a href="#改" class="headerlink" title="改"></a>改</h3><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">db.collection.updateOne(query, update, options)</span><br><span class="line">db.collection.updateMany(query, update, options)</span><br><span class="line"></span><br><span class="line">query: 查询条件</span><br><span class="line">update: 更新动作及新的内容</span><br><span class="line">options: 可选，配置</span><br><span class="line">upsert: boolean类型，默认false。设置为true后如果查询条件为空则插入</span><br><span class="line">writeConcern: 一个写操作落到多少节点才算成功</span><br></pre></td></tr></table></figure><p>更新操作符(update内容)</p><table><thead><tr><th>操作符</th><th>格式</th><th>描述</th></tr></thead><tbody><tr><td>$set</td><td><code>&#123;$set: &#123;field: value&#125;&#125;</code></td><td>指定一个键（字段）更新值，如果键不存在则创建</td></tr><tr><td>$unset</td><td><code>&#123;$unset: &#123;field: 1&#125;&#125;</code></td><td>删除一个键</td></tr><tr><td>$inc</td><td><code>&#123;$inc: &#123;field: number&#125;&#125;</code></td><td>对数值类型值进行加操作，number可以为负</td></tr><tr><td>$rename</td><td><code>&#123;$rename: &#123;oldFiled: newField&#125;&#125;</code></td><td>修改键的名称</td></tr><tr><td>$push</td><td><code>&#123;$push: &#123;field: value&#125;&#125;</code></td><td>将值添加到数组中，数组不存在则初始化</td></tr><tr><td>$pull</td><td><code>&#123;$pull: &#123;field: value&#125;&#125;</code></td><td>从数组中删除指定元素</td></tr><tr><td>$addToSet</td><td><code>&#123;$addToSet: &#123;field: value&#125;&#125;</code></td><td>添加元素到set集合（无序不重复）</td></tr><tr><td>$pop</td><td>&#96;{$pop: {field: 1</td><td>-1}}&#96;</td></tr></tbody></table><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051141033.png" alt="image-20221105114134991"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051141754.png" alt="image-20221105114147720"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051144867.png" alt="image-20221105114453806"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051149423.png" alt="image-20221105114922375"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051201526.png" alt="image-20221105120132480"></p><br><h3 id="查"><a href="#查" class="headerlink" title="查"></a>查</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">db.collection.find(query, projection)</span><br><span class="line"></span><br><span class="line">query: 可选。查询条件</span><br><span class="line">projection: 可选。选择要查询哪些键的值</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051210068.png" alt="image-20221105121036012"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051211105.png" alt="image-20221105121104068"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051212915.png" alt="image-20221105121204868"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051215287.png" alt="image-20221105121526242"></p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202211051215585.png" alt="image-20221105121555540"></p><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="数据库" scheme="https://blog.pushihao.com/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    <category term="NoSQL" scheme="https://blog.pushihao.com/tags/NoSQL/"/>
    
    <category term="MongoDB" scheme="https://blog.pushihao.com/tags/MongoDB/"/>
    
  </entry>
  
  <entry>
    <title>Python数据分析工具包-Numpy</title>
    <link href="https://blog.pushihao.com/article/66fbe6bf.html"/>
    <id>https://blog.pushihao.com/article/66fbe6bf.html</id>
    <published>2022-11-01T02:02:00.000Z</published>
    <updated>2022-11-01T02:02:00.000Z</updated>
    
    <content type="html"><![CDATA[<p><em>说明：通常所说的”数组”，”Numpy数组”，”ndarray”基本上都是指同一个东西，即ndarray对象。</em></p><h2 id="Numpy常用函数以及用法"><a href="#Numpy常用函数以及用法" class="headerlink" title="Numpy常用函数以及用法"></a>Numpy常用函数以及用法</h2><h3 id="（1）创建ndarray数组"><a href="#（1）创建ndarray数组" class="headerlink" title="（1）创建ndarray数组"></a>（1）创建ndarray数组</h3><blockquote><ol><li>使用array函数</li></ol></blockquote><p>说明：他可以接收一切序列型的对象，然后产生一个新的含有传入数据的Numpy数组。除非用dtype自定义类型，否则他会根据你传入的数据类型自动帮你匹配合适的类型。<br>此类型规则为：如果有字符串，则优先字符串，如果没有字符串而有复数类型，则系统默认帮你判定为复数类型。然后依次为浮点数和整数。即优先级为”字符串&gt;复数&gt;浮点数&gt;整数”。<br>代码如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">array = np.array([<span class="string">&#x27;Hello&#x27;</span>, <span class="number">1</span>+<span class="number">2j</span>, <span class="number">5.20</span>, <span class="number">5</span>])</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> array:</span><br><span class="line">    <span class="built_in">print</span>(i, <span class="string">&#x27;:&#x27;</span>, <span class="built_in">type</span>(i))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;===============================&#x27;</span>)</span><br><span class="line">array = np.array([<span class="number">1</span>+<span class="number">2j</span>, <span class="number">5.20</span>, <span class="number">5</span>])</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> array:</span><br><span class="line">    <span class="built_in">print</span>(i, <span class="string">&#x27;:&#x27;</span>, <span class="built_in">type</span>(i))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;===============================&#x27;</span>)</span><br><span class="line">array = np.array([<span class="number">5.20</span>, <span class="number">5</span>])</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> array:</span><br><span class="line">    <span class="built_in">print</span>(i, <span class="string">&#x27;:&#x27;</span>, <span class="built_in">type</span>(i))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;===============================&#x27;</span>)</span><br><span class="line">array = np.array([<span class="number">5</span>])</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> array:</span><br><span class="line">    <span class="built_in">print</span>(i, <span class="string">&#x27;:&#x27;</span>, <span class="built_in">type</span>(i))</span><br></pre></td></tr></table></figure><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">Hello : &lt;class &#x27;numpy.str_&#x27;&gt;</span><br><span class="line">(1+2j) : &lt;class &#x27;numpy.str_&#x27;&gt;</span><br><span class="line">5.2 : &lt;class &#x27;numpy.str_&#x27;&gt;</span><br><span class="line">5 : &lt;class &#x27;numpy.str_&#x27;&gt;</span><br><span class="line">===============================</span><br><span class="line">(1+2j) : &lt;class &#x27;numpy.complex128&#x27;&gt;</span><br><span class="line">(5.2+0j) : &lt;class &#x27;numpy.complex128&#x27;&gt;</span><br><span class="line">(5+0j) : &lt;class &#x27;numpy.complex128&#x27;&gt;</span><br><span class="line">===============================</span><br><span class="line">5.2 : &lt;class &#x27;numpy.float64&#x27;&gt;</span><br><span class="line">5.0 : &lt;class &#x27;numpy.float64&#x27;&gt;</span><br><span class="line">===============================</span><br><span class="line">5 : &lt;class &#x27;numpy.int32&#x27;&gt;</span><br></pre></td></tr></table></figure><blockquote><ol start="2"><li>使用ones和zeros函数</li></ol></blockquote><p>除此之外，还可以使用ones函数和zeros函数来创建一个全是1或者全是0的数组，我们只需要传递给他们一个需要创建的数组的形状即可。</p><p>代码示例如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">array = np.ones((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(array)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=================&#x27;</span>)</span><br><span class="line">array = np.zeros((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(array)</span><br></pre></td></tr></table></figure><p>输出结果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[[1. 1. 1.]</span><br><span class="line"> [1. 1. 1.]</span><br><span class="line"> [1. 1. 1.]]</span><br><span class="line">=================</span><br><span class="line">[[0. 0. 0.]</span><br><span class="line"> [0. 0. 0.]</span><br><span class="line"> [0. 0. 0.]]</span><br></pre></td></tr></table></figure><blockquote><ol start="3"><li>empty函数</li></ol></blockquote><p>函数说明：empty函数可以创建一个没有任何具体指的函数。我们在使用empty的时候只需要传入一个表示形状的元祖就可以了。值得注意的是，empty创建出来的数组初始值是不确定的随机值。<br>例如：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">array = np.empty((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(array)</span><br></pre></td></tr></table></figure><p>输出结果如下（完全没有规律）：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[[7.01573217e-322 0.00000000e+000 0.00000000e+000]</span><br><span class="line"> [0.00000000e+000 0.00000000e+000 1.14623230e-321]</span><br><span class="line"> [1.24610926e-306 1.61271680e-312 0.00000000e+000]</span><br></pre></td></tr></table></figure><blockquote><ol start="4"><li>arange函数</li></ol></blockquote><p>函数说明：arange函数用法与range函数类似。不同的是arange生成的是ndarray对象，即numpy数组。</p><p>例如运行如下代码：</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.arange(<span class="number">10</span>)</span><br><span class="line"><span class="built_in">print</span>(array1, <span class="built_in">type</span>(array1))</span><br></pre></td></tr></table></figure><p>输出结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[0 1 2 3 4 5 6 7 8 9] &lt;class &#x27;numpy.ndarray&#x27;&gt;</span><br></pre></td></tr></table></figure><blockquote><ol start="5"><li>linspace函数</li></ol></blockquote><p>函数说明：此函数与arange函数有些相似。调用方法为 np.linspace(start&#x3D; ,stop&#x3D; ,num&#x3D; ,endpoint&#x3D; ,retstep&#x3D; ,dtype&#x3D; ,axis&#x3D; )</p><p>参数说明：</p><ul><li><p>start是数组起始数字</p></li><li><p>stop是数组结束数字</p></li><li><p>num（可选）控制结果中共有多少个元素</p></li><li><p>endpoint（可选）决定了中止值（stop）是否包含在内。若值为True，则包含stop，否则不包含。如果不写默认是True</p></li><li><p>retstep（可选）默认是False，如果指定为True，则结果会返回步长以及序列数组，从而产生一个元组作为输出</p></li><li><p>dtype（可选）为生成的数组的类型，可以自定义数据类型，不写则按那个规则 字符串&gt;复数&gt;浮点数&gt;整数</p></li><li><p>axis（可选）默认是0 。很多函数都会有这个参数，这是个轴的意思。具体定义如下图：</p></li></ul><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202206101751445.png" alt="axis"> </p><p>运行如下代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.linspace(<span class="number">1</span>,<span class="number">10</span>,<span class="number">10</span>)</span><br><span class="line"><span class="built_in">print</span>(array1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span>*<span class="number">30</span>)</span><br><span class="line">array2 = np.linspace(start = <span class="number">1</span>, stop = <span class="number">10</span>, num = <span class="number">10</span>, endpoint=<span class="literal">True</span>, dtype=<span class="built_in">int</span>, retstep=<span class="literal">True</span>)</span><br><span class="line"><span class="built_in">print</span>(array2)</span><br></pre></td></tr></table></figure><p>输出结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]</span><br><span class="line">==============================</span><br><span class="line">(array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10]), 1.0)</span><br></pre></td></tr></table></figure><blockquote><ol start="6"><li>logspace函数</li></ol></blockquote><p>函数说明：返回在对数刻度上均匀间隔的数字。此函数尚未理解</p><blockquote><ol start="7"><li>full函数</li></ol></blockquote><p>函数说明：返回给定形状，给定值的数组。</p><p>运行代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.full(shape=(<span class="number">3</span>, <span class="number">3</span>), fill_value=<span class="number">10</span>, dtype=<span class="built_in">int</span>)</span><br><span class="line"><span class="built_in">print</span>(array)</span><br></pre></td></tr></table></figure><p>输出结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[[10 10 10]</span><br><span class="line"> [10 10 10]</span><br><span class="line"> [10 10 10]]</span><br></pre></td></tr></table></figure><blockquote><ol start="8"><li>repeat函数</li></ol></blockquote><p>函数说明：建立每个元素重复N次的数组。</p><p>运行代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.repeat(a=[<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], repeats=<span class="number">3</span>, axis=<span class="number">0</span>)  <span class="comment"># a的每个元素重复三次</span></span><br><span class="line"><span class="built_in">print</span>(array)</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[1 1 1 1 1 1 2 2 2 3 3 3]</span><br></pre></td></tr></table></figure><p>另外还有一些数组创建函数如下表所示：</p><table><thead><tr><th>函数</th><th>说明</th></tr></thead><tbody><tr><td>array</td><td>将输入数据（列表，元组，数组或者其他的序列类型）转换为ndarray。要么推断出dtype，要么在创建时即指定dtype。默认直接复制输入数据</td></tr><tr><td>asarray</td><td>将输入转换为ndarray，如果输入本身就是一个ndarray就不进行复制</td></tr><tr><td>arange</td><td>类似于内置的range，但返回的是一个ndarray而不是列表</td></tr><tr><td>ones、ones_like</td><td>ones是根据指定的dtype和形状创建一个全1数组，ones_like是根据给定的数组的形状创建一个全1数组</td></tr><tr><td>zeros、zeros_like</td><td>与上类似，只不过是全0数组</td></tr><tr><td>empty、empty_like</td><td>与上类似，只不过数据是随机的</td></tr><tr><td>eye、identity</td><td>创建一个N * N的单位矩阵，对角线元素为1，其余为0</td></tr><tr><td>full、full_like</td><td>创建一个给定形状，给定值的数组</td></tr></tbody></table><h3 id="（2）操作数组"><a href="#（2）操作数组" class="headerlink" title="（2）操作数组"></a>（2）操作数组</h3><h4 id="1-数组属性的获取"><a href="#1-数组属性的获取" class="headerlink" title="1. 数组属性的获取"></a>1. 数组属性的获取</h4><table><thead><tr><th>调用方法</th><th>作用</th></tr></thead><tbody><tr><td>.ndim</td><td>返回数组的维数</td></tr><tr><td>.shape</td><td>返回数组的形状</td></tr><tr><td>.size</td><td>返回数组元素个数</td></tr><tr><td>.dtype</td><td>返回数组元素类型</td></tr><tr><td>.itemsize</td><td>返回数组元素字节大小</td></tr></tbody></table><h4 id="2-数组属性的操作"><a href="#2-数组属性的操作" class="headerlink" title="2. 数组属性的操作"></a>2. 数组属性的操作</h4><table><thead><tr><th>调用方法</th><th>作用</th></tr></thead><tbody><tr><td>.reshape</td><td>改变数组形状</td></tr><tr><td>.all</td><td>数组元素都是0返回True，否则返回False</td></tr><tr><td>.any</td><td>数组元素有非0值返回True，否则返回False</td></tr><tr><td>.copy</td><td>复制数组副本（并不是引用）</td></tr><tr><td>.astype</td><td>改变数组元素数据类型</td></tr></tbody></table><h4 id="3-数组的对接与分割"><a href="#3-数组的对接与分割" class="headerlink" title="3. 数组的对接与分割"></a>3. 数组的对接与分割</h4><blockquote><ol><li>vstack()函数</li></ol></blockquote><p>函数说明：vstack()函数可以实现数组的垂直对接。</p><p>运行代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.zeros((<span class="number">2</span>, <span class="number">3</span>), dtype=<span class="built_in">int</span>)</span><br><span class="line">array2 = np.ones((<span class="number">4</span>, <span class="number">3</span>), dtype=<span class="built_in">int</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(array1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">20</span>)</span><br><span class="line"><span class="built_in">print</span>(array2)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">20</span>)</span><br><span class="line"><span class="built_in">print</span>(np.vstack((array1, array2)))</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">[[0 0 0]</span><br><span class="line"> [0 0 0]]</span><br><span class="line">====================</span><br><span class="line">[[1 1 1]</span><br><span class="line"> [1 1 1]</span><br><span class="line"> [1 1 1]</span><br><span class="line"> [1 1 1]]</span><br><span class="line">====================</span><br><span class="line">[[0 0 0]</span><br><span class="line"> [0 0 0]</span><br><span class="line"> [1 1 1]</span><br><span class="line"> [1 1 1]</span><br><span class="line"> [1 1 1]</span><br><span class="line"> [1 1 1]]</span><br></pre></td></tr></table></figure><blockquote><ol start="2"><li>hstack()</li></ol></blockquote><p>函数说明：hstack()函数可以实现数组元素的水平对接。</p><p>运行代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.zeros((<span class="number">2</span>, <span class="number">6</span>), dtype=<span class="built_in">int</span>)</span><br><span class="line">array2 = np.ones((<span class="number">2</span>, <span class="number">1</span>), dtype=<span class="built_in">int</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(array1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">20</span>)</span><br><span class="line"><span class="built_in">print</span>(array2)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">20</span>)</span><br><span class="line"><span class="built_in">print</span>(np.hstack((array1, array2)))</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[[0 0 0 0 0 0]</span><br><span class="line"> [0 0 0 0 0 0]]</span><br><span class="line">====================</span><br><span class="line">[[1]</span><br><span class="line"> [1]]</span><br><span class="line">====================</span><br><span class="line">[[0 0 0 0 0 0 1]</span><br><span class="line"> [0 0 0 0 0 0 1]]</span><br></pre></td></tr></table></figure><blockquote><ol start="3"><li>vsplit()</li></ol></blockquote><p>函数说明：vsplit(array, N)函数可以实现数组的垂直分割（就是分割的垂直，以水平方向分割垂直），array为需要分割的数组，N为分割数。</p><p>代码示例如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.array(([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>], [<span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]), dtype=<span class="built_in">int</span>)</span><br><span class="line"><span class="built_in">print</span>(array1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(np.vsplit(array1, <span class="number">3</span>))</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[[1 2 3]</span><br><span class="line"> [4 5 6]</span><br><span class="line"> [7 8 9]]</span><br><span class="line">==============================</span><br><span class="line">[array([[1, 2, 3]]), array([[4, 5, 6]]), array([[7, 8, 9]])]</span><br></pre></td></tr></table></figure><blockquote><ol start="4"><li>hsplit()</li></ol></blockquote><p>函数说明：hsplit(array, N)函数可以实现数组元素的水平分割（相当于以垂直方向分割水平，实现水平分割），array为要分割的数组，N为分割的份数。</p><p>代码示例如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.array(([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>], [<span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]), dtype=<span class="built_in">int</span>)</span><br><span class="line"><span class="built_in">print</span>(array1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(np.hsplit(array1, <span class="number">3</span>))</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[[1 2 3]</span><br><span class="line"> [4 5 6]</span><br><span class="line"> [7 8 9]]</span><br><span class="line">==============================</span><br><span class="line">[array([[1],</span><br><span class="line">       [4],</span><br><span class="line">       [7]]), array([[2],</span><br><span class="line">       [5],</span><br><span class="line">       [8]]), array([[3],</span><br><span class="line">       [6],</span><br><span class="line">       [9]])]</span><br></pre></td></tr></table></figure><h3 id="（3）多维数组的索引与切片（主要区别与一维数组不同的用法）"><a href="#（3）多维数组的索引与切片（主要区别与一维数组不同的用法）" class="headerlink" title="（3）多维数组的索引与切片（主要区别与一维数组不同的用法）"></a>（3）多维数组的索引与切片（主要区别与一维数组不同的用法）</h3><h4 id="1-索引省略用法"><a href="#1-索引省略用法" class="headerlink" title="1. 索引省略用法"></a>1. 索引省略用法</h4><p>说明：当能确定维度时，索引方法和普通数组一样，如array[1], array[1, 2], array[1, 2, 3]。当确定不了维度时，可以通过下标右边…省略号或直接省略下标数，来读取数组。</p><p>示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.arange(<span class="number">1</span>, <span class="number">13</span>).reshape((<span class="number">2</span>, <span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(array)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(array[<span class="number">1</span>])</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(array[<span class="number">1</span>, ])</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(array[<span class="number">1</span>, ...])</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(array[<span class="number">1</span>, ..., <span class="number">2</span>]) <span class="comment"># 此时不能用 array[1, 2]，会报错为: IndexErrorindex 2 is out of bounds for axis 1 with size 2</span></span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[[[ 1  2  3]</span><br><span class="line">  [ 4  5  6]]</span><br><span class="line"></span><br><span class="line"> [[ 7  8  9]</span><br><span class="line">  [10 11 12]]]</span><br><span class="line">==============================</span><br><span class="line">[[ 7  8  9]</span><br><span class="line"> [10 11 12]]</span><br><span class="line">==============================</span><br><span class="line">[[ 7  8  9]</span><br><span class="line"> [10 11 12]]</span><br><span class="line">==============================</span><br><span class="line">[[ 7  8  9]</span><br><span class="line"> [10 11 12]]</span><br><span class="line">==============================</span><br><span class="line">[ 9 12]</span><br></pre></td></tr></table></figure><h4 id="2-二维数组切片"><a href="#2-二维数组切片" class="headerlink" title="2. 二维数组切片"></a>2. 二维数组切片</h4><p>说明：默认的切片方式，如[0:2:1]获得第1行到第2行元素，这种切的是行，操作方式与一维数组相同，如果要切片二维数组的行和列，则</p><p>操作方式为：数组名[行切片, 列切片]</p><p>格式为：array[start:stop:step, start:stop:step]</p><p>如：array[:, 2]就是截取所有行，第三列的子数组。array[:, :]就是获取所有行所有列。</p><p>示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.arange(<span class="number">1</span>, <span class="number">13</span>).reshape((<span class="number">3</span>, <span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(array)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="comment"># 获取从第1行到第2行步长为1的所有行，再从这些行中获得第2列到第4列步长为2的所有元素</span></span><br><span class="line"><span class="built_in">print</span>(array[<span class="number">0</span>:<span class="number">2</span>:<span class="number">1</span>,<span class="number">1</span>:<span class="number">4</span>:<span class="number">2</span>])</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[[ 1  2  3  4]</span><br><span class="line"> [ 5  6  7  8]</span><br><span class="line"> [ 9 10 11 12]]</span><br><span class="line">==============================</span><br><span class="line">[[2 4]</span><br><span class="line"> [6 8]]</span><br></pre></td></tr></table></figure><h4 id="3-三维数组切片"><a href="#3-三维数组切片" class="headerlink" title="3. 三维数组切片"></a>3. 三维数组切片</h4><p>说明：操作方式与二维数组相类型，无非就是多了一维而已。</p><p>操作方式为：数组名[页切片, 行切片, 列切片]</p><p>格式为：array[start:stop:step, start:stop:step, start:stop:step]</p><p>示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.arange(<span class="number">1</span>, <span class="number">13</span>).reshape((<span class="number">2</span>, <span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(array)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="comment"># 获取第2页的第2行的从第2列到第3列步长为1的所有元素</span></span><br><span class="line"><span class="built_in">print</span>(array[<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>:<span class="number">3</span>:<span class="number">1</span>])</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[[[ 1  2  3]</span><br><span class="line">  [ 4  5  6]]</span><br><span class="line"></span><br><span class="line"> [[ 7  8  9]</span><br><span class="line">  [10 11 12]]]</span><br><span class="line">==============================</span><br><span class="line">[11 12]</span><br></pre></td></tr></table></figure><h4 id="4-花式索引"><a href="#4-花式索引" class="headerlink" title="4. 花式索引"></a>4. 花式索引</h4><blockquote><ol><li>整数数组索引</li></ol></blockquote><p>（1）一维数组的整数数组索引</p><p>说明：利用整数数组的所有元素的下标值进行索引，又叫数组索引。</p><p>示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">names = np.array([<span class="string">&#x27;zhaoer&#x27;</span>, <span class="string">&#x27;zhangsan&#x27;</span>, <span class="string">&#x27;lisi&#x27;</span>, <span class="string">&#x27;wangwu&#x27;</span>, <span class="string">&#x27;maliu&#x27;</span>, <span class="string">&#x27;tangqi&#x27;</span>])</span><br><span class="line">index = np.array([<span class="number">1</span>, <span class="number">2</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line"><span class="built_in">print</span>(*names)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">60</span>)</span><br><span class="line"><span class="built_in">print</span>(*names[index])</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">zhaoer zhangsan lisi wangwu maliu tangqi</span><br><span class="line">============================================================</span><br><span class="line">zhangsan lisi maliu tangqi</span><br></pre></td></tr></table></figure><p>（2）二维数组的数组索引</p><p>说明：对二维数组输出时如果只索引一个一维数组，则只操作行，如果索引为两个一维数组，则第一个一维数组指定结果的x坐标，第二个一维数组指定结果的y坐标。</p><p>示例如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line"><span class="comment"># 以下是利用一个整数数组进行索引</span></span><br><span class="line">names = np.array([[<span class="string">&#x27;tom&#x27;</span>, <span class="number">1</span>], [<span class="string">&#x27;jack&#x27;</span>, <span class="number">2</span>], [<span class="string">&#x27;lucy&#x27;</span>, <span class="number">3</span>], [<span class="string">&#x27;blackCat&#x27;</span>, <span class="number">4</span>], [<span class="string">&#x27;win&#x27;</span>, <span class="number">5</span>], [<span class="string">&#x27;father&#x27;</span>, <span class="number">6</span>]])</span><br><span class="line">index = np.array([<span class="number">1</span>, <span class="number">2</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line"><span class="built_in">print</span>(*names)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">60</span>)</span><br><span class="line"><span class="built_in">print</span>(*names[index])</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">60</span>)</span><br><span class="line"><span class="comment"># 以下用两个一维整数数组进行索引</span></span><br><span class="line">array = np.array([[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>], [<span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]])</span><br><span class="line">index1 = np.array([[<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>]]) <span class="comment"># 注意：这是其实是一个二维数组的第一维</span></span><br><span class="line">index2 = np.array([<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>])</span><br><span class="line"><span class="built_in">print</span>(array)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">60</span>)</span><br><span class="line"><span class="built_in">print</span>(array[index1, index2])</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[&#x27;tom&#x27; &#x27;1&#x27;] [&#x27;jack&#x27; &#x27;2&#x27;] [&#x27;lucy&#x27; &#x27;3&#x27;] [&#x27;blackCat&#x27; &#x27;4&#x27;] [&#x27;win&#x27; &#x27;5&#x27;] [&#x27;father&#x27; &#x27;6&#x27;]</span><br><span class="line">============================================================</span><br><span class="line">[&#x27;jack&#x27; &#x27;2&#x27;] [&#x27;lucy&#x27; &#x27;3&#x27;] [&#x27;win&#x27; &#x27;5&#x27;] [&#x27;father&#x27; &#x27;6&#x27;]</span><br><span class="line">============================================================</span><br><span class="line">[[1 2 3]</span><br><span class="line"> [4 5 6]</span><br><span class="line"> [7 8 9]]</span><br><span class="line">============================================================</span><br><span class="line">[[1 5 9]]</span><br></pre></td></tr></table></figure><blockquote><ol start="2"><li>bool数组索引</li></ol></blockquote><p>说明：准备一个bool数组，用该数组索引其他数组时，只会输出True位置对应的元素。一维或者多维数组都适用。</p><p>示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.arange(<span class="number">1</span>, <span class="number">10</span>).reshape((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line">index = np.array([[<span class="literal">True</span>, <span class="literal">False</span>, <span class="literal">True</span>], [<span class="literal">True</span>, <span class="literal">False</span>, <span class="literal">False</span>], [<span class="literal">False</span>, <span class="literal">False</span>, <span class="literal">True</span>]])</span><br><span class="line"><span class="built_in">print</span>(array)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">20</span>)</span><br><span class="line"><span class="built_in">print</span>(array[index])</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[[1 2 3]</span><br><span class="line"> [4 5 6]</span><br><span class="line"> [7 8 9]]</span><br><span class="line">====================</span><br><span class="line">[1 3 4 9]</span><br></pre></td></tr></table></figure><h3 id="（4）基本数学计算"><a href="#（4）基本数学计算" class="headerlink" title="（4）基本数学计算"></a>（4）基本数学计算</h3><h4 id="1-普通计算"><a href="#1-普通计算" class="headerlink" title="1. 普通计算"></a>1. 普通计算</h4><p>说明：计算的对象可以是两个数组，也可以是一个数组一个数字，所有运算对于复数也同样适用。如下表：</p><table><thead><tr><th>运算方式</th><th>符号</th><th>函数</th></tr></thead><tbody><tr><td>数组加法</td><td>+</td><td>add</td></tr><tr><td>数组减法</td><td>-</td><td>subtract</td></tr><tr><td>数组乘法</td><td>*</td><td>multiply</td></tr><tr><td>数组除法</td><td>&#x2F;</td><td>divide</td></tr><tr><td>数组求余</td><td>%</td><td>mod</td></tr><tr><td>数组求幂</td><td>**</td><td>power</td></tr><tr><td>数组整除</td><td>&#x2F;&#x2F;</td><td>floor_divide</td></tr></tbody></table><p>示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.arange(<span class="number">1</span>, <span class="number">10</span>).reshape((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line">array2 = np.array([<span class="number">10</span>, <span class="number">10</span>, <span class="number">10</span>])</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;第一个数组：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(array1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;第二个数组：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(array2)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组加法：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.add(array1, array2))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组减法：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.subtract(array1, array2))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组乘法：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.multiply(array1, <span class="number">2</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组除法：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.divide(array1, <span class="number">10</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组求余：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.mod(array1, array2))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组求幂：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.power(array1, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;数组整除：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.floor_divide(array1, <span class="number">2</span>))</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">第一个数组：</span><br><span class="line">[[1 2 3]</span><br><span class="line"> [4 5 6]</span><br><span class="line"> [7 8 9]]</span><br><span class="line">第二个数组：</span><br><span class="line">[10 10 10]</span><br><span class="line">==============================</span><br><span class="line">数组加法：</span><br><span class="line">[[11 12 13]</span><br><span class="line"> [14 15 16]</span><br><span class="line"> [17 18 19]]</span><br><span class="line">==============================</span><br><span class="line">数组减法：</span><br><span class="line">[[-9 -8 -7]</span><br><span class="line"> [-6 -5 -4]</span><br><span class="line"> [-3 -2 -1]]</span><br><span class="line">==============================</span><br><span class="line">数组乘法：</span><br><span class="line">[[ 2  4  6]</span><br><span class="line"> [ 8 10 12]</span><br><span class="line"> [14 16 18]]</span><br><span class="line">==============================</span><br><span class="line">数组除法：</span><br><span class="line">[[0.1 0.2 0.3]</span><br><span class="line"> [0.4 0.5 0.6]</span><br><span class="line"> [0.7 0.8 0.9]]</span><br><span class="line">==============================</span><br><span class="line">数组求余：</span><br><span class="line">[[1 2 3]</span><br><span class="line"> [4 5 6]</span><br><span class="line"> [7 8 9]]</span><br><span class="line">==============================</span><br><span class="line">数组求幂：</span><br><span class="line">[[  1   8  27]</span><br><span class="line"> [ 64 125 216]</span><br><span class="line"> [343 512 729]]</span><br><span class="line">==============================</span><br><span class="line">数组整除：</span><br><span class="line">[[0 1 1]</span><br><span class="line"> [2 2 3]</span><br><span class="line"> [3 4 4]]</span><br></pre></td></tr></table></figure><h4 id="2-比较运算"><a href="#2-比较运算" class="headerlink" title="2. 比较运算"></a>2. 比较运算</h4><p>说明：可以数组与数组比较，也可以数组和单个数字标量进行比较，结果是与第一个数组形状相同的数组，满足条件的位置为True，不满足的为False，如下表：</p><table><thead><tr><th>运算方式</th><th>符号</th></tr></thead><tbody><tr><td>等于比较</td><td>&#x3D;&#x3D;</td></tr><tr><td>不等于比较</td><td>!&#x3D;</td></tr><tr><td>大于比较</td><td>&gt;</td></tr><tr><td>小于比较</td><td>&lt;</td></tr><tr><td>大于等于</td><td>&gt;&#x3D;</td></tr><tr><td>小于等于</td><td>&lt;&#x3D;</td></tr></tbody></table><p>示例（此示例仅展示等于比较运算，其他运算方式相似）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.arange(<span class="number">1</span>, <span class="number">10</span>).reshape((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line">array2 = np.array([<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>])</span><br><span class="line"><span class="built_in">print</span>(array1 == array2)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(array1 == <span class="number">1</span>)</span><br></pre></td></tr></table></figure><p>结果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[[ True False False]</span><br><span class="line"> [False False False]</span><br><span class="line"> [False False False]]</span><br><span class="line">==============================</span><br><span class="line">[[ True False False]</span><br><span class="line"> [False False False]</span><br><span class="line"> [False False False]]</span><br></pre></td></tr></table></figure><h4 id="3-数组位运算"><a href="#3-数组位运算" class="headerlink" title="3. 数组位运算"></a>3. 数组位运算</h4><p>说明：运算对象可以是数组与数组，也可以是数组和单个数字标量，结果是与第一个数组形状相同的数组，满足条件的位置为True，不满足的为False，如下表：</p><table><thead><tr><th>运算方式</th><th>符号</th></tr></thead><tbody><tr><td>与</td><td>&amp;</td></tr><tr><td>或</td><td>|</td></tr><tr><td>非</td><td>~</td></tr><tr><td>左移</td><td>&lt;&lt;</td></tr><tr><td>右移</td><td>&gt;&gt;</td></tr></tbody></table><p>示例（次示例仅展示与运算，其他运算方式类似）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array1 = np.arange(<span class="number">1</span>, <span class="number">10</span>).reshape((<span class="number">3</span>, <span class="number">3</span>))</span><br><span class="line">array2 = np.array([[<span class="literal">True</span>, <span class="literal">False</span>, <span class="literal">True</span>], [<span class="literal">True</span>, <span class="literal">False</span>, <span class="literal">True</span>], [<span class="literal">True</span>, <span class="literal">False</span>, <span class="literal">True</span>]])</span><br><span class="line"><span class="built_in">print</span>(array1 &amp; array2)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(array1 &amp; <span class="number">10</span>)</span><br></pre></td></tr></table></figure><p>运算结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[[1 0 1]</span><br><span class="line"> [0 0 0]</span><br><span class="line"> [1 0 1]]</span><br><span class="line">==============================</span><br><span class="line">[[0 2 2]</span><br><span class="line"> [0 0 2]</span><br><span class="line"> [2 8 8]]</span><br></pre></td></tr></table></figure><h3 id="（5）数组通用函数"><a href="#（5）数组通用函数" class="headerlink" title="（5）数组通用函数"></a>（5）数组通用函数</h3><p><em><strong>说明：这里的函数和数学概念中的函数是一一对应的</strong></em></p><h4 id="1-三角函数-反三角函数"><a href="#1-三角函数-反三角函数" class="headerlink" title="1. 三角函数 反三角函数"></a>1. 三角函数 反三角函数</h4><p>说明：</p><ul><li>numpy中自带圆周率，用numpy.pi就可以使用</li><li>传递给函数的数是以弧度计算，对于角度可以用array * numpy.pi &#x2F; 180 转换为弧度</li><li>调用反三角函数时可以用numpy.degrees()函数将结果中的弧度转换为角度</li></ul><p>函数如下表：</p><table><thead><tr><th>功能</th><th>函数</th></tr></thead><tbody><tr><td>正弦</td><td>sin</td></tr><tr><td>余弦</td><td>cos</td></tr><tr><td>正切</td><td>tan</td></tr><tr><td>反正弦</td><td>arcsin</td></tr><tr><td>反余弦</td><td>arccos</td></tr><tr><td>反正切</td><td>arctan</td></tr></tbody></table><p>以正弦为示例，其他类似：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.array([<span class="number">0</span>, <span class="number">30</span>, <span class="number">45</span>, <span class="number">60</span>, <span class="number">90</span>])</span><br><span class="line">sin = np.sin(array * np.pi / <span class="number">180</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;正弦计算结果为：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(sin)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;=&#x27;</span> * <span class="number">60</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;对结果执行反正弦并转换为角度：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.degrees(np.arcsin(sin)))</span><br></pre></td></tr></table></figure><p>运行结果如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">正弦计算结果为：</span><br><span class="line">[0.         0.5        0.70710678 0.8660254  1.        ]</span><br><span class="line">============================================================</span><br><span class="line">对结果执行反正弦并转换为角度：</span><br><span class="line">[ 0. 30. 45. 60. 90.]</span><br></pre></td></tr></table></figure><h4 id="2-舍入函数"><a href="#2-舍入函数" class="headerlink" title="2. 舍入函数"></a>2. 舍入函数</h4><p>函数：numpy.around(array, decimals)</p><p>函数说明：</p><ul><li>其中array为数组，decimals为要保留的小数位数，默认值为0，如果为负数，则将整数四舍五入保留到小数点左侧位置</li><li>结果是科学计数法的形式，如1.23e + 2就是1.23*10^2</li></ul><p>示例如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">array = np.array([<span class="number">12</span>, <span class="number">12.123456</span>, <span class="number">12345.12</span>])</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;将decimals默认：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.around(array))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;保留到小数点后一位：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.around(array, <span class="number">1</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;保留到小数点左一位：&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(np.around(array, -<span class="number">1</span>))</span><br></pre></td></tr></table></figure><p>运行结果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">将decimals默认：</span><br><span class="line">[1.2000e+01 1.2000e+01 1.2345e+04]</span><br><span class="line">保留到小数点后一位：</span><br><span class="line">[1.20000e+01 1.21000e+01 1.23451e+04]</span><br><span class="line">保留到小数点左一位：</span><br><span class="line">[1.000e+01 1.000e+01 1.235e+04]</span><br></pre></td></tr></table></figure><h4 id="3-取整函数"><a href="#3-取整函数" class="headerlink" title="3. 取整函数"></a>3. 取整函数</h4><p>说明：</p><ul><li>numpy.ceil(array)是返回大于或者等于指定表达式的最小整数，即向上取整。</li><li>numpy.floor(array)是返回小于或等于指定表达式的最大整数，即向下取整。</li><li>参数中array是数组名。</li></ul><h4 id="4-以e为底的指数函数和对数函数"><a href="#4-以e为底的指数函数和对数函数" class="headerlink" title="4. 以e为底的指数函数和对数函数"></a>4. 以e为底的指数函数和对数函数</h4><p>说明：</p><ul><li>numpy.exp(array)是以e为底，以array为指数的结果。</li><li>numpy.log(array)是以e为底，以array为真数的结果。</li><li>numpy.log2(array)是以2为底，以array为真数的结果。</li><li>numpy.log10(array)是以10为底，以array为真数的结果。</li><li>其中array既可以是数组，也可以是单个数字标量。</li></ul><h4 id="5-随机函数"><a href="#5-随机函数" class="headerlink" title="5. 随机函数"></a>5. 随机函数</h4><p>说明：常用随机函数如下表</p><table><thead><tr><th>函数</th><th>参数</th><th>解释</th></tr></thead><tbody><tr><td>numpy.random.rand(shape)</td><td>shape用于指定生成数组的形状</td><td>函数产生[0, )范围内的浮点随机数，生成一个数组</td></tr><tr><td>numpy.random.randn(shape)</td><td>shape用于指定生成数组的形状</td><td>函数产生标准正态分布随机数，生成一个数组</td></tr><tr><td>numpy.random.randint(low&#x3D;None, high&#x3D;None, size&#x3D;None, dtype&#x3D;None)</td><td>随机数范围[low, high)，size是随机数的个数，dtype是随机数类型</td><td>生成的type类型的size个范围内的随机数，返回一个数组</td></tr><tr><td></td><td></td><td></td></tr><tr><td>numpy.random.normal(loc&#x3D;None, scale&#x3D;None, size&#x3D;None)</td><td></td><td>产生正态分布随机数</td></tr><tr><td>numpy.random.uniform(low&#x3D;None, high&#x3D;None, size&#x3D;None)</td><td></td><td>产生均匀分布随机数</td></tr><tr><td>numpy.random.poisson(lam&#x3D;None, size&#x3D;None)</td><td></td><td>产生泊松分布随机数</td></tr><tr><td></td><td></td><td></td></tr><tr><td>numpy.random.permutation(array)</td><td>array可以是数组，也可以是单独数字标量</td><td>当array为数组时，打乱数组中的所有数，当array为数字标量时，返回[0, array)范围内的数的乱序组成的数组</td></tr><tr><td>numpy.random.shuffle(array)</td><td>array为数组</td><td>与上述区别是直接对array进行打乱，无返回值</td></tr></tbody></table>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Python" scheme="https://blog.pushihao.com/tags/Python/"/>
    
    <category term="Numpy" scheme="https://blog.pushihao.com/tags/Numpy/"/>
    
    <category term="数据分析" scheme="https://blog.pushihao.com/tags/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/"/>
    
  </entry>
  
  <entry>
    <title>解决 CLion 中文乱码问题</title>
    <link href="https://blog.pushihao.com/article/aed84cd9.html"/>
    <id>https://blog.pushihao.com/article/aed84cd9.html</id>
    <published>2022-10-29T14:24:00.000Z</published>
    <updated>2022-10-29T14:24:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>CLion 在输出中文时会发生乱码，找了网上的一些教程，都是说更改编码为 GBK。这样虽然能解决问题，但是很麻烦，因为每次都要更改</p><p>用下述方法，只需设置一次，不用像其他教程重复设置</p><h2 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h2><p>快捷键Ctrl+Shift+Alt+&#x2F;，弹出如下界面：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205150936015.png" alt="20200812201012"></p><p>然后，取消第一项的勾选，也就是run.processes.with.pty</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205150936847.png" alt="20200812201103"></p><p>这样就成功解决了，完美！</p><p>测试一下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;你好世界!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="CLion" scheme="https://blog.pushihao.com/tags/CLion/"/>
    
    <category term="乱码" scheme="https://blog.pushihao.com/tags/%E4%B9%B1%E7%A0%81/"/>
    
  </entry>
  
  <entry>
    <title>搭建 RLCraft 服务器</title>
    <link href="https://blog.pushihao.com/article/dca4faa5.html"/>
    <id>https://blog.pushihao.com/article/dca4faa5.html</id>
    <published>2022-10-17T12:35:00.000Z</published>
    <updated>2022-10-17T12:35:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>RLCraft 是一款好评如潮的 Minecraft 整合包。在原生 Minecraft 的基础上做了多样的扩展，可玩性非常高。关于此扩展包的具体介绍可在如下网站查看：<a href="https://www.curseforge.com/minecraft/modpacks/rlcraft">https://www.curseforge.com/minecraft/modpacks/rlcraft</a></p><p>将它运行在服务器上，就可以和好朋友一起玩了。</p><p>需要注意的是 RLCraft 只是一个代表性的例子。此方法适用于大部分 Forge Server 的搭建，不过具体的细节还是要看官网的介绍。</p><br><h2 id="前期准备"><a href="#前期准备" class="headerlink" title="前期准备"></a>前期准备</h2><ol><li>JDK8</li></ol><p>一定要是 JDK8，新版的 JDK 17 无法运行我们需要的旧版本的 Forge1.12.2 服务器。下载地址：<a href="https://www.oracle.com/sg/java/technologies/javase/javase8-archive-downloads.html">https://www.oracle.com/sg/java/technologies/javase/javase8-archive-downloads.html</a></p><ol start="2"><li>Forge1.12.2 - 14.23.5.2860</li></ol><p>下载地址：<a href="https://maven.minecraftforge.net/net/minecraftforge/forge/1.12.2-14.23.5.2860/forge-1.12.2-14.23.5.2860-installer.jar">https://maven.minecraftforge.net/net/minecraftforge/forge/1.12.2-14.23.5.2860/forge-1.12.2-14.23.5.2860-installer.jar</a></p><ol start="3"><li>RLCraft2.9.1</li></ol><p>下载地址：<a href="https://mediafilez.forgecdn.net/files/3655/676/RLCraft+Server+Pack+1.12.2+-+Release+v2.9.1c.zip">https://mediafilez.forgecdn.net/files/3655/676/RLCraft+Server+Pack+1.12.2+-+Release+v2.9.1c.zip</a></p><blockquote><p>Forge 和 RLCraft 要放在同一个文件夹内</p></blockquote><p>完成效果图（举例）：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172055610.png" alt="image-20221017205506501"></p><br><h2 id="安装服务器"><a href="#安装服务器" class="headerlink" title="安装服务器"></a>安装服务器</h2><ol><li>将 RLCraft 解压缩</li></ol><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">unzip RLCraft+Server+Pack+1.12.2+-+Release+v2.9.1c.zip</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172057279.png" alt="image-20221017205751240"></p><ol start="2"><li>修改 server.properties 配置文件</li></ol><p>必须要设置如下几个部分，其他部分在知情的情况下可自行修改：</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">allow-flight</span>=<span class="string">true</span></span><br><span class="line"><span class="attr">difficulty</span>=<span class="string">3</span></span><br><span class="line"><span class="attr">max-tick-time</span>=<span class="string">-1</span></span><br><span class="line"><span class="attr">enable-command-block</span>=<span class="string">true</span></span><br></pre></td></tr></table></figure><ol start="3"><li>安装 Forge 服务器</li></ol><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">/usr/local/jdk/jdk1.8.0_202/bin/java -jar forge-1.12.2-14.23.5.2860-installer.jar --installServer</span><br></pre></td></tr></table></figure><p>结尾出现如下字样即为安装成功</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172103547.png" alt="image-20221017210325504"></p><ol start="4"><li>启动 Forge 服务器</li></ol><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">/usr/local/jdk/jdk1.8.0_202/bin/java -jar forge-1.12.2-14.23.5.2860.jar nogui</span><br></pre></td></tr></table></figure><p>不出意外的话程序会报错并退出</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172105819.png" alt="image-20221017210534783"></p><p>原因：我们没有同意什么用户协议什么的</p><ol start="5"><li>同意用户协议</li></ol><p>修改 eula.txt 文件，将 eula 设置为 true</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172108767.png" alt="image-20221017210819733"></p><ol start="6"><li>启动服务器</li></ol><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">/usr/local/jdk/jdk1.8.0_202/bin/java -jar forge-1.12.2-14.23.5.2860.jar nogui</span><br></pre></td></tr></table></figure><p>这步需要等待较长时间，而且中间会各种爆红、卡顿什么的，只要不闪退就不用管他，耐心等待就好。出现如下字样即为启动成功</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172114315.png" alt="image-20221017211448271"></p><br><p>至此，服务端就搭建完成了！</p><ol start="6"><li>放开端口</li></ol><p>如果没做修改的话，Forge 服务器默认运行在 25565 端口，在防火墙中开启此端口即可</p><br><h2 id="开始游戏"><a href="#开始游戏" class="headerlink" title="开始游戏"></a>开始游戏</h2><p>打开 Minecraft 启动器，点击多人游戏，输入名称和公网IP地址，连接服务器，一气呵成</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202210172143341.png" alt="image-20221017214321097"></p><br><p>祝您游戏愉快！</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="技术杂谈" scheme="https://blog.pushihao.com/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/"/>
    
    
    <category term="Minecraft" scheme="https://blog.pushihao.com/tags/Minecraft/"/>
    
    <category term="Forge" scheme="https://blog.pushihao.com/tags/Forge/"/>
    
    <category term="RLCraft" scheme="https://blog.pushihao.com/tags/RLCraft/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot读取配置文件</title>
    <link href="https://blog.pushihao.com/article/4e8ba2c.html"/>
    <id>https://blog.pushihao.com/article/4e8ba2c.html</id>
    <published>2022-09-30T11:12:00.000Z</published>
    <updated>2022-09-30T11:12:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>配置文件一般存放一些系统变量或用户变量，例如数据库数据源的配置。它可以实现在不改变程序源代码的情况下修改程序的变量的值。通过配置文件可以使程序开发变得更加灵活。接下来我将介绍几种常见的在 SpringBoot 中获取配置文件的方式。</p><p>我的示例配置文件(userinfo.yml)位置如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209302037823.png" alt="image-20220930203751776"></p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">my-profile:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">grape</span></span><br><span class="line">  <span class="attr">age:</span> <span class="number">6</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="attr">users:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">张三</span></span><br><span class="line">    <span class="attr">age:</span> <span class="number">20</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">李四</span></span><br><span class="line">    <span class="attr">age:</span> <span class="number">21</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">王五</span></span><br><span class="line">    <span class="attr">age:</span> <span class="number">22</span></span><br></pre></td></tr></table></figure><br><h2 id="通过-value-读取简单信息"><a href="#通过-value-读取简单信息" class="headerlink" title="通过 @value 读取简单信息"></a>通过 <code>@value</code> 读取简单信息</h2><p>通过在变量前加上注解 <code>@value(&quot;$&#123;xxx&#125;&quot;)</code> 可以将配置信息注入到变量中</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.pushihao.bean.YmlConfigFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.PropertySource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@PropertySource(value = &#123;&quot;classpath:userinfo.yml&quot;&#125;,encoding=&quot;UTF-8&quot;,factory = YmlConfigFactory.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserinfoController</span> &#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;my-profile.name&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;my-profile.age&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String age;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/u1&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">u1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;name:&quot;</span> + name + <span class="string">&quot;|age:&quot;</span> + age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>注意：</p><p>@PropertySource 注解可以指定要读取的配置文件的位置。不写此注解默认读取SpringBoot默认配置文件application.properties&#x2F;application.yml&#x2F;application.yaml。</p><p>因为 @PropertySource 注解默认是读取 properties 文件，所以如果是读取 properties 文件，注解可以写成 @PropertySource(value &#x3D; {“classpath:userinfo.properties”},encoding&#x3D;”UTF-8”)。</p><p>本例中读取的是 yml 文件，需要重写 DefaultPropertySourceFactory，让其加载 yml 文件。然后在 PropertySource 注解中加入<code>factory = YmlConfigFactory.class</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.bean;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.config.YamlPropertiesFactoryBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.env.PropertiesPropertySource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.env.PropertySource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.io.support.DefaultPropertySourceFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.io.support.EncodedResource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.util.Properties;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">YmlConfigFactory</span> <span class="keyword">extends</span> <span class="title class_">DefaultPropertySourceFactory</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> PropertySource&lt;?&gt; createPropertySource(String name, EncodedResource resource) <span class="keyword">throws</span> IOException, IOException &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">sourceName</span> <span class="operator">=</span> name != <span class="literal">null</span> ? name : resource.getResource().getFilename();</span><br><span class="line">        <span class="keyword">if</span> (!resource.getResource().exists()) &#123;</span><br><span class="line">            <span class="keyword">assert</span> sourceName != <span class="literal">null</span>;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PropertiesPropertySource</span>(sourceName, <span class="keyword">new</span> <span class="title class_">Properties</span>());</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">assert</span> sourceName != <span class="literal">null</span>;</span><br><span class="line">            <span class="keyword">if</span> (sourceName.endsWith(<span class="string">&quot;.yml&quot;</span>) || sourceName.endsWith(<span class="string">&quot;.yaml&quot;</span>)) &#123;</span><br><span class="line">                <span class="type">Properties</span> <span class="variable">propertiesFromYaml</span> <span class="operator">=</span> loadYml(resource);</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PropertiesPropertySource</span>(sourceName, propertiesFromYaml);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="built_in">super</span>.createPropertySource(name, resource);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Properties <span class="title function_">loadYml</span><span class="params">(EncodedResource resource)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">YamlPropertiesFactoryBean</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">YamlPropertiesFactoryBean</span>();</span><br><span class="line">        factory.setResources(resource.getResource());</span><br><span class="line">        factory.afterPropertiesSet();</span><br><span class="line">        <span class="keyword">return</span> factory.getObject();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></blockquote><br><h2 id="通过-Environment-读取配置文件"><a href="#通过-Environment-读取配置文件" class="headerlink" title="通过 Environment 读取配置文件"></a>通过 Environment 读取配置文件</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.pushihao.bean.YmlConfigFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.PropertySource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.env.Environment;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@PropertySource(value = &#123;&quot;classpath:userinfo.yml&quot;&#125;,encoding=&quot;UTF-8&quot;,factory = YmlConfigFactory.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Userinfo2Controller</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Environment environment;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/u2&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">u2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> environment.getProperty(<span class="string">&quot;my-profile.name&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">age</span> <span class="operator">=</span> environment.getProperty(<span class="string">&quot;my-profile.age&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;name:&quot;</span> + name + <span class="string">&quot;|age:&quot;</span> + age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><h2 id="通过-ConfigurationProperties-读取配置文件"><a href="#通过-ConfigurationProperties-读取配置文件" class="headerlink" title="通过 @ConfigurationProperties 读取配置文件"></a>通过 <code>@ConfigurationProperties</code> 读取配置文件</h2><p>@ConfigurationProperties 注解可以将配置文件映射成一个类，而配置文件中的每个键就对应类中的每个属性</p><p>映射类代码如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.bean;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.context.properties.ConfigurationProperties;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.PropertySource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@PropertySource(value = &#123;&quot;classpath:userinfo.yml&quot;&#125;,encoding=&quot;UTF-8&quot;,factory = YmlConfigFactory.class)</span></span><br><span class="line"><span class="comment">//注意：prefix指定的是键的前缀，而不是文件名的前缀</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserinfoProperties</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//注意：此处的变量名称要和配置文件中的键的名称相对应，采用驼峰命名法</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">User</span> <span class="variable">myProfile</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> List&lt;User&gt; users = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Data</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">        String name;</span><br><span class="line"></span><br><span class="line">        Integer age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.pushihao.bean.UserinfoProperties;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Userinfo3Controller</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserinfoProperties userinfoProperties;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/u3&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">u3</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;name:&quot;</span> + userinfoProperties.getMyProfile().getName()</span><br><span class="line">                + <span class="string">&quot;|age:&quot;</span> + userinfoProperties.getMyProfile().getAge()</span><br><span class="line">                + <span class="string">&quot;|users:&quot;</span> + userinfoProperties.getUsers().toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>配置文件优先级</p><p>位置决定优先级：</p><p>Config data files are considered in the following order:</p><ol><li><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files">Application properties</a> packaged inside your jar ( and YAML variants).<code>application.properties</code></li><li><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files.profile-specific">Profile-specific application properties</a> packaged inside your jar ( and YAML variants).<code>application-&#123;profile&#125;.properties</code></li><li><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files">Application properties</a> outside of your packaged jar ( and YAML variants).<code>application.properties</code></li><li><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files.profile-specific">Profile-specific application properties</a> outside of your packaged jar ( and YAML variants).<code>application-&#123;profile&#125;.properties</code></li></ol><br><p>文件后缀名决定优先级：</p><p>yml 读取优先级 &gt; properties 读取优先级</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Java" scheme="https://blog.pushihao.com/tags/Java/"/>
    
    <category term="SpringBoot" scheme="https://blog.pushihao.com/tags/SpringBoot/"/>
    
  </entry>
  
  <entry>
    <title>Centos 配置 LNMP 环境</title>
    <link href="https://blog.pushihao.com/article/8e6dd1c3.html"/>
    <id>https://blog.pushihao.com/article/8e6dd1c3.html</id>
    <published>2022-09-15T11:58:58.000Z</published>
    <updated>2024-11-09T10:34:20.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>手把手教你配置 LNMP 环境，其中大部分学习过程中需要用到的模块也在安装过程中一并安装了，或许是初学者的福音😁😁</p></blockquote><h2 id="版本说明"><a href="#版本说明" class="headerlink" title="版本说明"></a>版本说明</h2><p>请注意不同版本号的软件的安装方式和软件兼容性可能有差别！！！</p><table><thead><tr><th>软件名</th><th>版本号</th><th>官网</th><th>下载链接</th></tr></thead><tbody><tr><td>Linux</td><td>Centos8.0</td><td><a href="https://www.centos.org/">https://www.centos.org/</a></td><td>&#x2F;</td></tr><tr><td>Nginx</td><td>1.23.1</td><td><a href="https://www.nginx.com/">https://www.nginx.com/</a></td><td><a href="https://nginx.org/download/nginx-1.23.1.tar.gz">https://nginx.org/download/nginx-1.23.1.tar.gz</a></td></tr><tr><td>MySQL</td><td>8.0.30</td><td><a href="https://www.mysql.com/">https://www.mysql.com/</a></td><td><a href="https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.30-1.el8.x86_64.rpm-bundle.tar">https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.30-1.el8.x86_64.rpm-bundle.tar</a></td></tr><tr><td>PHP</td><td>8.0.23</td><td><a href="https://www.php.net/">https://www.php.net/</a></td><td><a href="https://www.php.net/distributions/php-8.0.23.tar.gz">https://www.php.net/distributions/php-8.0.23.tar.gz</a></td></tr></tbody></table><br><h2 id="编译安装-Nginx"><a href="#编译安装-Nginx" class="headerlink" title="编译安装 Nginx"></a>编译安装 Nginx</h2><ol><li>下载</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /usr/local/nginx</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> /usr/local/nginx</span><br><span class="line"></span><br><span class="line">wget https://nginx.org/download/nginx-1.23.1.tar.gz</span><br></pre></td></tr></table></figure><ol start="2"><li>安装依赖</li></ol><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">yum -y install gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel</span><br></pre></td></tr></table></figure><ol start="3"><li>编译</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">tar -zxvf nginx-1.23.1.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> nginx-1.23.1/</span><br><span class="line"></span><br><span class="line">./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_sub_module --with-http_gzip_static_module --with-pcre</span><br></pre></td></tr></table></figure><ol start="4"><li>安装</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make &amp;&amp; make install</span><br></pre></td></tr></table></figure><ol start="5"><li>添加环境变量(可选)</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/profile</span><br></pre></td></tr></table></figure><p>将光标移动到最后一行，添加如下内容(按 <code>i</code> 进入输入模式，输入完成之后按 <code>esc</code> 进入命令模式，输入 <code>:wq</code> 回车即可保存并退出)：<code>export PATH=$PATH:/usr/local/nginx/sbin</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /etc/profile</span><br></pre></td></tr></table></figure><ol start="6"><li>检验</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx -V</span><br></pre></td></tr></table></figure><p>至此，Nginx 安装完毕，离成功进了一步！</p><br><h2 id="安装-MySQL"><a href="#安装-MySQL" class="headerlink" title="安装 MySQL"></a>安装 MySQL</h2><ol><li>首先检查系统中是否已经有了 MySQL</li></ol><p>检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">rpm -qa | grep mysql</span><br><span class="line">rpm -qa | grep mariadb</span><br></pre></td></tr></table></figure><p>运行后如果没有反应那就是没事，如果有的话，就运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm -e ***  (***为对应的软件名称)</span><br></pre></td></tr></table></figure><ol start="2"><li>安装依赖包</li></ol><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">yum -y install ncurses-devel libaio-devel libaio</span><br></pre></td></tr></table></figure><ol start="3"><li>下载MySQL</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /usr/local/mysql</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> /usr/local/mysql</span><br><span class="line"></span><br><span class="line">wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.30-1.el8.x86_64.rpm-bundle.tar</span><br></pre></td></tr></table></figure><ol start="4"><li>解压MySQL</li></ol><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">tar -xvf mysql-8.0.30-1.el8.x86_64.rpm-bundle.tar</span><br></pre></td></tr></table></figure><ol start="5"><li>安装MySQL</li></ol><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></pre></td><td class="code"><pre><span class="line">rpm -ivh mysql-community-common-8.0.30-1.el8.x86_64.rpm</span><br><span class="line"></span><br><span class="line">rpm -ivh mysql-community-client-plugins-8.0.30-1.el8.x86_64.rpm</span><br><span class="line"></span><br><span class="line">rpm -ivh mysql-community-libs-8.0.30-1.el8.x86_64.rpm</span><br><span class="line"></span><br><span class="line">rpm -ivh mysql-community-client-8.0.30-1.el8.x86_64.rpm</span><br><span class="line"></span><br><span class="line">rpm -ivh mysql-community-icu-data-files-8.0.30-1.el8.x86_64.rpm</span><br><span class="line"></span><br><span class="line">rpm -ivh mysql-community-server-8.0.30-1.el8.x86_64.rpm</span><br></pre></td></tr></table></figure><p>至此，MySQL 就安装完毕了，我们离成功又近了一步。</p><ol start="6"><li>启动 MySQL</li></ol><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">systemctl start mysqld</span><br></pre></td></tr></table></figure><ol start="7"><li>重置 MySQL 的 root 密码</li></ol><p>MySQL 会有一个初识密码，通过命令获得临时密码：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">&quot;password&quot;</span> /var/log/mysqld.log</span><br></pre></td></tr></table></figure><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209152159984.png" alt="image-20220915215909934"></p><p>登录(密码是不会显示的，放心输入)：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -u root -p</span><br></pre></td></tr></table></figure><p>输入如下命令进行改密码：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">alter user user() identified by <span class="string">&quot;******&quot;</span>;  (******为密码，需包含大小写字母、数字以及符号，不然报错密码过于简单)</span><br><span class="line"></span><br><span class="line">flush privileges;</span><br></pre></td></tr></table></figure><ol start="8"><li>设置数据库可以以 root 身份远程访问</li></ol><p>以 root 身份登录 MySQL，然后执行如下命令：</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">use mysql;</span><br><span class="line"></span><br><span class="line">create user <span class="string">&#x27;root&#x27;</span>@<span class="string">&#x27;%&#x27;</span> identified by <span class="string">&#x27;******&#x27;</span>; //******为自己设置的密码</span><br><span class="line"></span><br><span class="line">grant all privileges on *.* to <span class="string">&#x27;root&#x27;</span>@<span class="string">&#x27;%&#x27;</span> with grant option;</span><br><span class="line"></span><br><span class="line">flush privileges;</span><br></pre></td></tr></table></figure><p>马上就要成功了，只差最后一个PHP！！！</p><br><h2 id="编译安装-PHP"><a href="#编译安装-PHP" class="headerlink" title="编译安装 PHP"></a>编译安装 PHP</h2><ol><li>下载</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /usr/local/php</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> /usr/local/php</span><br><span class="line"></span><br><span class="line">wget https://www.php.net/distributions/php-8.0.23.tar.gz</span><br></pre></td></tr></table></figure><ol start="2"><li>安装依赖</li></ol><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">yum install -y libtool automake sqlite* gcc gcc-c++  make zlib zlib-devel pcre pcre-devel  libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5* openldap* nss_ldap</span><br></pre></td></tr></table></figure><ol start="3"><li>有个依赖需要单独安装</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">wget https://github.com/kkos/oniguruma/archive/v6.9.4.tar.gz -O oniguruma-6.9.4.tar.gz</span><br><span class="line"></span><br><span class="line">tar -zxvf oniguruma-6.9.4.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> oniguruma-6.9.4</span><br><span class="line"></span><br><span class="line">./autogen.sh &amp;&amp; ./configure --prefix=/usr</span><br><span class="line"></span><br><span class="line">make &amp;&amp; make install</span><br></pre></td></tr></table></figure><ol start="4"><li>编译</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /usr/local/php</span><br><span class="line"></span><br><span class="line">tar -zxvf php-8.0.23.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> php-8.0.23/</span><br><span class="line"></span><br><span class="line">./configure \</span><br><span class="line">--prefix=/usr/local/php \</span><br><span class="line">--with-config-file-path=/usr/local/php \</span><br><span class="line">--enable-mbstring \</span><br><span class="line">--with-openssl \</span><br><span class="line">--enable-ftp \</span><br><span class="line">--with-gd \</span><br><span class="line">--with-jpeg-dir=/usr \</span><br><span class="line">--with-png-dir=/usr \</span><br><span class="line">--with-mysql=mysqlnd \</span><br><span class="line">--with-mysqli=mysqlnd \</span><br><span class="line">--with-pdo-mysql=mysqlnd \</span><br><span class="line">--with-pear \</span><br><span class="line">--enable-sockets \</span><br><span class="line">--with-freetype-dir=/usr \</span><br><span class="line">--with-zlib \</span><br><span class="line">--with-libxml-dir=/usr \</span><br><span class="line">--with-xmlrpc \</span><br><span class="line">--enable-zip \</span><br><span class="line">--enable-fpm \</span><br><span class="line">--enable-xml \</span><br><span class="line">--enable-sockets \</span><br><span class="line">--with-gd \</span><br><span class="line">--with-zlib \</span><br><span class="line">--with-iconv \</span><br><span class="line">--enable-zip \</span><br><span class="line">--with-freetype-dir=/usr/lib/ \</span><br><span class="line">--enable-soap \</span><br><span class="line">--enable-pcntl \</span><br><span class="line">--enable-cli \</span><br><span class="line">--with-curl</span><br></pre></td></tr></table></figure><ol start="5"><li>安装</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make &amp;&amp; make install</span><br></pre></td></tr></table></figure><ol start="6"><li>使用默认的配置文件</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> php.ini-production /etc/php.ini</span><br><span class="line"></span><br><span class="line"><span class="built_in">cp</span> /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf</span><br><span class="line"></span><br><span class="line"><span class="built_in">cp</span> /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf</span><br><span class="line"></span><br><span class="line"><span class="built_in">cp</span> sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm</span><br><span class="line"></span><br><span class="line"><span class="built_in">chmod</span> +x /etc/init.d/php-fpm</span><br></pre></td></tr></table></figure><ol start="7"><li>增加用户和组</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">adduser www             <span class="comment">#增加用户</span></span><br><span class="line"></span><br><span class="line">passwd www              <span class="comment">#为用户设置密码</span></span><br><span class="line"></span><br><span class="line">groupadd www            <span class="comment">#增加组</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 以下两条命令二选一</span></span><br><span class="line">usermod -G www www     <span class="comment">#将用户移动到指定组，删除用户之前的组，前面是username，后面是groupname</span></span><br><span class="line"></span><br><span class="line">gpasswd -a www www     <span class="comment">#将用户移动到指定组，不删除该用户之前的组，前面是username，后面是groupname</span></span><br></pre></td></tr></table></figure><ol start="8"><li>配置用户和用户组</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /usr/local/php/etc/php-fpm.d/www.conf</span><br></pre></td></tr></table></figure><p>修改如下内容</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209152133094.png" alt="image-20220915213306963"></p><ol start="9"><li>添加环境变量(可选)</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/profile</span><br></pre></td></tr></table></figure><p>将光标移动到最后一行，添加如下内容(按 <code>i</code> 进入输入模式，输入完成之后按 <code>esc</code> 进入命令模式，输入 <code>:wq</code> 回车即可保存并退出)：<code>export PATH=$PATH:/usr/local/php/bin</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /etc/profile</span><br></pre></td></tr></table></figure><ol start="10"><li>验证</li></ol><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">php --version</span><br></pre></td></tr></table></figure><br><p>至此，恭喜您 LNMP 环境搭建完毕！接下来愉快的敲代码吧😘😘</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="环境搭建" scheme="https://blog.pushihao.com/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    
    <category term="Linux" scheme="https://blog.pushihao.com/tags/Linux/"/>
    
    <category term="Centos" scheme="https://blog.pushihao.com/tags/Centos/"/>
    
    <category term="Nginx" scheme="https://blog.pushihao.com/tags/Nginx/"/>
    
    <category term="Mysql" scheme="https://blog.pushihao.com/tags/Mysql/"/>
    
    <category term="PHP" scheme="https://blog.pushihao.com/tags/PHP/"/>
    
  </entry>
  
  <entry>
    <title>部署项目时遇到的坑</title>
    <link href="https://blog.pushihao.com/article/859028d4.html"/>
    <id>https://blog.pushihao.com/article/859028d4.html</id>
    <published>2022-09-09T01:34:31.000Z</published>
    <updated>2022-09-09T01:34:31.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>前端时间学习过程中写了几个小 Demo，但都是在本机开发环境下运行的。本以为部署到服务器就是简单把文件上传就可以。结果踩了一些很可笑的坑🤣🤣</p><br><h2 id="部署普通-JavaEE-项目"><a href="#部署普通-JavaEE-项目" class="headerlink" title="部署普通 JavaEE 项目"></a>部署普通 JavaEE 项目</h2><p>这个比较简单，用 Maven 把项目打成 War 包，然后上传至 Tomcat 目录的 webapps 目录下，并且启动 Tomcat 服务即可。Tomcat 会自动将 War 包进行解压缩。然后访问 ip:port&#x2F;project_name-project_version 即可看到项目首页。</p><p><strong>需要注意的是：项目中的所有涉及到路径跳转的 url 都尽量使用相对路径</strong></p><br><h2 id="部署-Spring-Boot-项目"><a href="#部署-Spring-Boot-项目" class="headerlink" title="部署 Spring Boot 项目"></a>部署 Spring Boot 项目</h2><h3 id="问题说明"><a href="#问题说明" class="headerlink" title="问题说明"></a>问题说明</h3><p>我使用的 IDE 是 Intellij IDEA，开发时项目在本地运行正常。使用 Maven 将其打包后，运行 <code>java -jar test-2.0-SNAPSHOT.jar</code> 出现错误：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209091006182.png" alt="image-20220909100617063"></p><p>翻译过来就是：这个 jar 包中没有主清单属性</p><br><h3 id="原因解读"><a href="#原因解读" class="headerlink" title="原因解读"></a>原因解读</h3><p>出现此问题的原因是打包后的 jar 文件中的 MANIFEST.MF 缺少项目启动项。我们用压缩软件打开 jar 包，查看 META-INF 下的 MANIFEST.MF 文件</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209091020002.png" alt="image-20220909102021957"></p><p>第一时间想到的是没有 Start-Class 配置项</p><br><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>在项目中添加 spring-boot-maven-plugin 打包插件。</p><p>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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">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">version</span>&gt;</span>2.6.7<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.pushihao<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>test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>17<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-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><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.github.penggle<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>kaptcha<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.3.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!--此处即为添加上述插件--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><p>再次打包，查看 META-INF 下的 MANIFEST.MF 文件</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209091026608.png" alt="image-20220909102621563"></p><p>会发现多了一些相关配置属性，此时再运行 <code>java -jar test-2.0-SNAPSHOT.jar</code> 一切正常</p><br><h2 id="部署-vue-项目"><a href="#部署-vue-项目" class="headerlink" title="部署 vue 项目"></a>部署 vue 项目</h2><h3 id="问题说明-1"><a href="#问题说明-1" class="headerlink" title="问题说明"></a>问题说明</h3><p>构建环境我使用的是 vue3 + vite</p><p>为了解决跨域问题，我使用了 vite 提供的代理设置</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; defineConfig &#125; <span class="keyword">from</span> <span class="string">&#x27;vite&#x27;</span></span><br><span class="line"><span class="keyword">import</span> vue <span class="keyword">from</span> <span class="string">&#x27;@vitejs/plugin-vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// https://vitejs.dev/config/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>(&#123;</span><br><span class="line">  <span class="attr">plugins</span>: [<span class="title function_">vue</span>()],</span><br><span class="line">  <span class="attr">server</span>: &#123;</span><br><span class="line">    <span class="attr">proxy</span>: &#123;</span><br><span class="line">      <span class="string">&quot;/api&quot;</span>: &#123;</span><br><span class="line">        <span class="attr">target</span>: <span class="string">&quot;http://152.136.233.95:8090/&quot;</span>,</span><br><span class="line">        <span class="attr">changeOrigin</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">rewrite</span>: <span class="function">(<span class="params">path</span>) =&gt;</span> path.<span class="title function_">replace</span>(<span class="regexp">/^\/api/</span>, <span class="string">&quot;&quot;</span>),</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">disableHostCheck</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>项目在本地运行正常。通过 <code>yarn run build</code> 构建打包，上传到服务器，通过 nginx 创建服务器</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span>  <span class="number">10989</span>;</span><br><span class="line">    <span class="attribute">server_name</span> localhost;</span><br><span class="line"></span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">root</span> html/test2;</span><br><span class="line">        <span class="attribute">index</span> index.html;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>浏览项目地址。发现项目的 ajax 请求出现 404 错误</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209091047508.png" alt="image-20220909104717468"></p><br><h3 id="原因解读-1"><a href="#原因解读-1" class="headerlink" title="原因解读"></a>原因解读</h3><p>vite 提供的代理服务器在实际项目中不起作用，仅在开发阶段可以使用</p><br><h3 id="解决方案-1"><a href="#解决方案-1" class="headerlink" title="解决方案"></a>解决方案</h3><p><strong>使用 nginx 进行代理</strong></p><p>其中使用 nginx 在后端代理的方式在我的上一篇博客<a href="https://www.pushihao.com/article/34a1b75a.html">浅谈 xhr 请求跨域问题</a>已经提到了，这里主要介绍使用 nginx 在前端进行反向代理</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span>  <span class="number">10989</span>;</span><br><span class="line">    <span class="attribute">server_name</span> localhost;</span><br><span class="line"></span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">root</span> html/test2;</span><br><span class="line">        <span class="attribute">index</span> index.html;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="section">location</span> /api/ &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://152.136.233.95:8090/;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>重启 nginx 服务，前端请求正常，问题解决！</p><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Nginx" scheme="https://blog.pushihao.com/tags/Nginx/"/>
    
    <category term="vue" scheme="https://blog.pushihao.com/tags/vue/"/>
    
    <category term="项目部署" scheme="https://blog.pushihao.com/tags/%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2/"/>
    
  </entry>
  
  <entry>
    <title>浅谈 xhr 请求跨域问题</title>
    <link href="https://blog.pushihao.com/article/34a1b75a.html"/>
    <id>https://blog.pushihao.com/article/34a1b75a.html</id>
    <published>2022-09-07T05:02:55.000Z</published>
    <updated>2022-09-07T05:02:55.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题引出"><a href="#问题引出" class="headerlink" title="问题引出"></a>问题引出</h2><p>我在 <a href="http://localhost:8080/">http://localhost:8080</a> 放了一台后端服务器</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/h1&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">h1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, world!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>通过调用 <a href="http://localhost:8080/hello/h1">http://localhost:8080/hello/h1</a> 可以获得一个字符串</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209071314082.png" alt="image-20220907131446988"></p><br><p>我又在 <a href="http://localhost:5173/">http://localhost:5173</a> 放了一台前端前端服务器，通过 xhr 请求调用后端的接口</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></pre></td><td class="code"><pre><span class="line">&lt;script setup&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line">axios.defaults.timeout = 5000</span><br><span class="line"></span><br><span class="line">axios.get(&quot;http://localhost:8080/hello/h1&quot;).then(</span><br><span class="line">    response =&gt; &#123;</span><br><span class="line">      console.log(response)</span><br><span class="line">    &#125;, error =&gt; &#123;</span><br><span class="line">      console.log(error)</span><br><span class="line">    &#125;</span><br><span class="line">)</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;template&gt;&lt;/template&gt;</span><br><span class="line">&lt;style scoped&gt;&lt;/style&gt;</span><br></pre></td></tr></table></figure><p>结果这时，浏览器报错</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209071319602.png" alt="image-20220907131920563"></p><br><p>以上便是 xhr 请求跨域问题的一个经典例子</p><br><h2 id="为什么会有请求跨域问题"><a href="#为什么会有请求跨域问题" class="headerlink" title="为什么会有请求跨域问题"></a>为什么会有请求跨域问题</h2><p>什么导致的跨域请求问题？简单来说，浏览器的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy">同源策略</a> 导致了跨域请求问题。</p><p>为什么要制定同源策略？官方是这样解释的：同源策略是一个重要的安全策略，它用于限制一个 <a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Origin">origin</a> 的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档，减少可能被攻击的媒介。</p><p>什么样的 url 才算是同源呢？当两个 url 的**协议(protocol)<strong>、</strong>域名(host)<strong>、</strong>端口(port)**三者都相同时才算是同源。只要其中有一个不同，那么 url 就不算同源，进行的 http 请求就称为跨域请求。</p><p>跨域请求有什么限制？无法读取非同源网页的 cookie、localstorage 等、无法接触非同源网页的 DOM 和 js 对象、无法向非同源地址发送 Ajax 请求。</p><br><h2 id="解决跨域请求问题"><a href="#解决跨域请求问题" class="headerlink" title="解决跨域请求问题"></a>解决跨域请求问题</h2><p>我们知道，同源策略是一个重要的安全策略，它可以减少我们被攻击的风险。但是对于正常的请求，我们希望可以接触跨域带来的一些限制。解决跨域请求问题的方法有很多，以下给出一些常用的解决方案。</p><h3 id="后端使用-nginx-解决跨域问题"><a href="#后端使用-nginx-解决跨域问题" class="headerlink" title="后端使用 nginx 解决跨域问题"></a>后端使用 nginx 解决跨域问题</h3><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">3500</span>;</span><br><span class="line">    <span class="attribute">server_name</span> localhost;</span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment"># 给 Nginx 配置 Access-Control-Allow-Origin * 后，表示服务器可以接受所有的请求源（Origin）,即接受所有跨域的请求。也就是说，表示接受任意域名的请求。这里为 * 是最简单粗暴的方式，但是出于安全考虑，一般会设置为前端域名，如：add_header Access-Control-Allow-Origin &#x27;www.pushihao.com&#x27;;（只能指定一个域）</span></span><br><span class="line">        <span class="attribute">add_header</span> Access-Control-Allow-Origin *;</span><br><span class="line">        </span><br><span class="line">        <span class="comment"># 如果是上述设置为 * 的话，浏览器将不会发送 cookie 数据（如果需要携带 cookie 数据，则需要进行此设置</span></span><br><span class="line">        <span class="attribute">add_header</span> Access-Control-Allow-Credentials <span class="literal">true</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment"># 防止出现 Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. 错误</span></span><br><span class="line">        <span class="attribute">add_header</span> Access-Control-Allow-Methods <span class="string">&#x27;GET, POST, OPTIONS&#x27;</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment"># 防止出现 Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. 错误</span></span><br><span class="line">        <span class="attribute">add_header</span> Access-Control-Allow-Headers <span class="string">&#x27;DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization&#x27;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 防止在发送 post 请求时 Nginx 依然拒绝访问的错误。发送&quot;预检请求&quot;时，需要用到方法OPTIONS,所以服务器需要允许该方法</span></span><br><span class="line">        <span class="attribute">if</span> (<span class="variable">$request_method</span> = <span class="string">&#x27;OPTIONS&#x27;</span>) &#123;</span><br><span class="line">            <span class="attribute">return</span> <span class="number">204</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">proxy_pass</span> http://localhost:8080;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>启动 Nginx 服务后，3500 端口被代理到 8080 端口，并且开启了允许所有域进行跨域请求</p><p>此时，修改前端请求的 url</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;script setup&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line">axios.defaults.timeout = 5000</span><br><span class="line"></span><br><span class="line">axios.get(&quot;http://localhost:3500/hello/h1&quot;).then(</span><br><span class="line">    response =&gt; &#123;</span><br><span class="line">      console.log(response)</span><br><span class="line">    &#125;, error =&gt; &#123;</span><br><span class="line">      console.log(error)</span><br><span class="line">    &#125;</span><br><span class="line">)</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;template&gt;&lt;/template&gt;</span><br><span class="line">&lt;style scoped&gt;&lt;/style&gt;</span><br></pre></td></tr></table></figure><p>启动服务后，请求响应正常</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209071441959.png" alt="image-20220907144118916"></p><br><h3 id="使用前端框架提供的代理服务器"><a href="#使用前端框架提供的代理服务器" class="headerlink" title="使用前端框架提供的代理服务器"></a>使用前端框架提供的代理服务器</h3><blockquote><p>注意：这种方法仅在调试阶段有效，部署到服务器上之后就没用了</p></blockquote><p>使用原理：</p><p>只有前端在发送 Ajax 请求时会触发跨域请求，而两台后端服务器进行通信时是不会存在跨域的问题的，因此我们可以在前端与后端之间设置一台代理服务器，这台代理服务器与我们的前端项目保持同源，即：<code>localhost:5173</code> ，我们的前端项目只负责请求这台代理服务器，由代理服务器向后端接口请求数据。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202209071456708.png" alt="image-20220907145652664"></p><ol><li>对于 webpack + vue 的前端项目，可以使用 devServer 配置代理解决跨域问题</li></ol><p>vue.config.js</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; defineConfig &#125; = <span class="built_in">require</span>(<span class="string">&#x27;@vue/cli-service&#x27;</span>)</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title function_">defineConfig</span>(&#123;</span><br><span class="line">  <span class="attr">transpileDependencies</span>: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">//开启代理服务器(方式一)</span></span><br><span class="line">  <span class="comment">// devServer: &#123;</span></span><br><span class="line">  <span class="comment">//   proxy: &quot;http://localhost:8080&quot;</span></span><br><span class="line">  <span class="comment">// &#125;</span></span><br><span class="line">  <span class="comment">//只能由一个代理服务器，而且会优先请求本地资源，无法决定请求资源的位置</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="comment">//开启代理服务器(方式二)</span></span><br><span class="line">  <span class="attr">devServer</span>: &#123;</span><br><span class="line">    <span class="attr">proxy</span>: &#123;</span><br><span class="line">      <span class="string">&#x27;/api&#x27;</span>: &#123;</span><br><span class="line">        <span class="attr">target</span>: <span class="string">&#x27;http://localhost:8080&#x27;</span>,</span><br><span class="line">        <span class="comment">//重写请求路径，把/api去掉</span></span><br><span class="line">        <span class="attr">pathRewrite</span>: &#123;</span><br><span class="line">          <span class="string">&#x27;^/api&#x27;</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">ws</span>: <span class="literal">true</span>, <span class="comment">//用于支持websocket</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//等于true时会有跨域伪造，即：如果请求的目标服务器为8080，则请求时也假装自己是8080端口的</span></span><br><span class="line">        <span class="comment">//等于false时面对目标服务器就如实回答</span></span><br><span class="line">        <span class="attr">changeOrigin</span>: <span class="literal">true</span></span><br><span class="line">      &#125;,</span><br><span class="line"></span><br><span class="line">      <span class="comment">//proxy可配置多个</span></span><br><span class="line">      <span class="string">&#x27;/teacher&#x27;</span>: &#123;</span><br><span class="line">        <span class="attr">target</span>: <span class="string">&#x27;http://localhost:8082&#x27;</span>,</span><br><span class="line">        <span class="attr">pathRewrite</span>: &#123;</span><br><span class="line">          <span class="string">&#x27;^/teacher&#x27;</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">ws</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">changeOrigin</span>: <span class="literal">true</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>AxiosTest.vue</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&lt;script setup&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line">axios.defaults.timeout = 5000</span><br><span class="line"></span><br><span class="line">// 由于我们制定了重写规则，所以此处的 /api 会在发送请求时被略去</span><br><span class="line">axios.get(&quot;/api/hello/h1&quot;).then(</span><br><span class="line">    response =&gt; &#123;</span><br><span class="line">      console.log(response)</span><br><span class="line">    &#125;, error =&gt; &#123;</span><br><span class="line">      console.log(error)</span><br><span class="line">    &#125;</span><br><span class="line">)</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;template&gt;&lt;/template&gt;</span><br><span class="line">&lt;style scoped&gt;&lt;/style&gt;</span><br></pre></td></tr></table></figure><br><ol start="2"><li>对于 vite + vue 的前端项目</li></ol><p>vite.config.js</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; defineConfig &#125; <span class="keyword">from</span> <span class="string">&#x27;vite&#x27;</span></span><br><span class="line"><span class="keyword">import</span> vue <span class="keyword">from</span> <span class="string">&#x27;@vitejs/plugin-vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// https://vitejs.dev/config/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>(&#123;</span><br><span class="line">  <span class="attr">plugins</span>: [<span class="title function_">vue</span>()],</span><br><span class="line">  <span class="attr">server</span>: &#123;</span><br><span class="line">    <span class="attr">proxy</span>: &#123;</span><br><span class="line">      <span class="string">&quot;/api&quot;</span>: &#123;</span><br><span class="line">        <span class="attr">target</span>: <span class="string">&quot;http://localhost:8080&quot;</span>,</span><br><span class="line">        <span class="attr">changeOrigin</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">rewrite</span>: <span class="function">(<span class="params">path</span>) =&gt;</span> path.<span class="title function_">replace</span>(<span class="regexp">/^\/api/</span>, <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><span class="line"></span><br></pre></td></tr></table></figure><p>AxiosTest.vue</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;script setup&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line">axios.defaults.timeout = 5000</span><br><span class="line"></span><br><span class="line">axios.get(&quot;/api/hello/h1&quot;).then(</span><br><span class="line">    response =&gt; &#123;</span><br><span class="line">      console.log(response)</span><br><span class="line">    &#125;, error =&gt; &#123;</span><br><span class="line">      console.log(error)</span><br><span class="line">    &#125;</span><br><span class="line">)</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;template&gt;&lt;/template&gt;</span><br><span class="line">&lt;style scoped&gt;&lt;/style&gt;</span><br></pre></td></tr></table></figure><p>至此，问题解决！</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="JS" scheme="https://blog.pushihao.com/tags/JS/"/>
    
    <category term="前端" scheme="https://blog.pushihao.com/tags/%E5%89%8D%E7%AB%AF/"/>
    
    <category term="Java" scheme="https://blog.pushihao.com/tags/Java/"/>
    
    <category term="vue" scheme="https://blog.pushihao.com/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>JavaScript 学习笔记</title>
    <link href="https://blog.pushihao.com/article/cedc43fd.html"/>
    <id>https://blog.pushihao.com/article/cedc43fd.html</id>
    <published>2022-09-02T02:31:07.000Z</published>
    <updated>2022-09-02T02:31:07.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引入"><a href="#引入" class="headerlink" title="引入"></a>引入</h2><p>JavaScript 是一种轻量级、跨平台和<strong>解释编译</strong>的编程语言，也称为网页脚本语言。它以开发网页而闻名，但是许多非浏览器环境也可以使用它。JavaScript 可用于客户端开发以及服务器端开发。它既是命令式又是声明式语言。作为前端三件套之中唯一有编程逻辑的语言，JavaScript 常常用于页面交互、实现一些复杂的动画以及数据传输等。</p><br><h2 id="浏览器工作原理"><a href="#浏览器工作原理" class="headerlink" title="浏览器工作原理"></a>浏览器工作原理</h2><p>浏览器分为两个部分：渲染引擎和 JS 引擎</p><ul><li>渲染引擎：用来解析HTML和CSS，俗称内核，比如 chrome 的blink，老版本的 webkit</li><li>JS 引擎：也成为 JS 解释器。用来读取网页中的 JavaScript 代码，对其进行后台处理，比如 chrome 浏览器的 v8</li></ul><blockquote><p>注意：浏览器本身不会执行 JS 代码，而是通过内置 JavaScript 引擎（解释器）来执行JS代码，JS 引擎执行代码时会逐行解释每一行源码（转化为机器语言），然后由计算机去执行</p></blockquote><br><h2 id="JS-组成"><a href="#JS-组成" class="headerlink" title="JS 组成"></a>JS 组成</h2><h3 id="ECMAScript"><a href="#ECMAScript" class="headerlink" title="ECMAScript"></a>ECMAScript</h3><p><strong>ECMAScript</strong> 是由 ECMA 国际（原欧洲计算机制造商协会）进行标准化的一门编程语言，它规定了 JS 的编程语法和基础核心知识，是所有浏览器厂商共同遵守的一套 JS 语法<strong>工业标准</strong></p><h3 id="DOM"><a href="#DOM" class="headerlink" title="DOM"></a>DOM</h3><p><strong>DOM</strong>（Document Object Model，文档对象模型）是 W3C 组织推荐的处理可扩展标记语言（HTML或XML）的标准<strong>编程接口</strong>。通过此接口我们可以很容易的对页面上的元素的属性进行操作</p><h3 id="BOM"><a href="#BOM" class="headerlink" title="BOM"></a>BOM</h3><p><strong>BOM</strong>（Browser Object Model，浏览器对象模型）是一种独立于内容的，与浏览器窗口进行互动的对象结构。通过 BOM 可以操作浏览器窗口，比如弹出框、浏览器跳转、获取窗口大小、滚动条、分辨率等</p><br><h2 id="JS-数据类型及运算符"><a href="#JS-数据类型及运算符" class="headerlink" title="JS 数据类型及运算符"></a>JS 数据类型及运算符</h2><blockquote><p>JS 是一种弱类型的语言，也就是说某一个变量被定义类型之后，该变量可以根据环境变化自动进行转换，不需要强制转换</p></blockquote><h3 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h3><ol><li><p>使用单引号或双引号包裹</p></li><li><p>\ 为转义字符，通过 \ ，可以打印 Unicode Ascll 字符等</p></li><li><p>多行字符串编写</p></li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> msg = <span class="string">`</span></span><br><span class="line"><span class="string">hello</span></span><br><span class="line"><span class="string">world</span></span><br><span class="line"><span class="string">你好</span></span><br><span class="line"><span class="string">世界`</span></span><br></pre></td></tr></table></figure><ol start="4"><li>模板字符串</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> name = <span class="string">&#x27;Pillage&#x27;</span></span><br><span class="line"><span class="keyword">let</span> age = <span class="number">19</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> msg = <span class="string">`你好啊, <span class="subst">$&#123;name&#125;</span>`</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span><br><span class="line"></span><br><span class="line">&gt; 你好啊, <span class="title class_">Pillage</span></span><br></pre></td></tr></table></figure><ol start="5"><li>字符串长度</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">str.<span class="property">length</span></span><br></pre></td></tr></table></figure><ol start="6"><li>可变性：不可变</li><li>大小写转化（对中文没有影响）</li></ol><figure class="highlight js"><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="title function_">toUpperCase</span>();</span><br><span class="line">.<span class="title function_">toLowerCase</span>();</span><br></pre></td></tr></table></figure><ol start="8"><li>寻找索引</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.<span class="title function_">indexOf</span>(<span class="string">&#x27;t&#x27;</span>)</span><br></pre></td></tr></table></figure><ol start="9"><li>截取字符串</li></ol><figure class="highlight js"><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="title function_">substring</span>(<span class="number">1</span>)    <span class="comment">//从下标为1开始截取，包括下标为1的，一直截到最后</span></span><br><span class="line">.<span class="title function_">substring</span>(<span class="number">1</span>, <span class="number">3</span>) <span class="comment">//前闭后开</span></span><br></pre></td></tr></table></figure><br><h3 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h3><p>注意：for in 是遍历下标， for of 才是遍历数组具体的值</p><p>Array 可以包含任意的数据类型</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> array = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="string">&quot;Hello&quot;</span>]</span><br></pre></td></tr></table></figure><ol><li>长度</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="property">length</span></span><br></pre></td></tr></table></figure><p>注意：此属性可读可写，即可以通过赋值修改数组的大小</p><ol start="2"><li>寻找索引</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="title function_">indexOf</span>(<span class="number">1</span>)</span><br></pre></td></tr></table></figure><ol start="3"><li>截取数组，返回一个新数组</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="title function_">slice</span>()</span><br></pre></td></tr></table></figure><p>类似于 String 中的 substring</p><ol start="4"><li>操作元素（在尾部）</li></ol><figure class="highlight js"><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">array.<span class="title function_">push</span>()</span><br><span class="line">array.<span class="title function_">pop</span>()</span><br></pre></td></tr></table></figure><ol start="5"><li>操作元素（在头部）</li></ol><figure class="highlight js"><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">array.<span class="property">unshift</span>   <span class="comment">//压入到头部</span></span><br><span class="line">array.<span class="property">shift</span>     <span class="comment">//弹出头部的一个元素</span></span><br></pre></td></tr></table></figure><ol start="6"><li>排序</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="title function_">sort</span>()</span><br></pre></td></tr></table></figure><ol start="7"><li>元素反转</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="title function_">reverse</span>()</span><br></pre></td></tr></table></figure><ol start="8"><li>数组拼接</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="title function_">concat</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>])</span><br></pre></td></tr></table></figure><p>注意：concat() 并不会修改原数组，只会返回一个连接后的新数组</p><ol start="9"><li>连接数组</li></ol><p>打印拼接数组，使用特定的字符串连接</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array.<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>)</span><br></pre></td></tr></table></figure><ol start="10"><li>多维数组</li></ol><p>类似于 Python。例如二维数组就是一个普通一维数组中的每一个元素又是一个一维数组</p><br><h3 id="对象"><a href="#对象" class="headerlink" title="对象"></a>对象</h3><p>定义：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 对象名 = &#123;</span><br><span class="line">    属性名：属性值，</span><br><span class="line">    属性名：属性值，</span><br><span class="line">    ...</span><br><span class="line">    属性名：属性值</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> person =  &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&quot;pillage&quot;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">18</span>,</span><br><span class="line">    <span class="attr">score</span>: <span class="number">100</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>JS 中，大括号可以表示一个对象，用键值对描述属性，多个属性之间用逗号隔开，最后一个不需要逗号</p><p>JS 中，所有的键都是字符串，值可以是任意类型</p><ol><li>对象赋值</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">person.<span class="property">age</span> = <span class="number">19</span></span><br></pre></td></tr></table></figure><ol start="2"><li>动态增删属性</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//动态删减 name 属性</span></span><br><span class="line"><span class="keyword">delete</span> person.<span class="property">name</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//动态增加 sex 属性,只需要给新属性赋值即可</span></span><br><span class="line">person.<span class="property">sex</span> = <span class="string">&quot;男&quot;</span></span><br></pre></td></tr></table></figure><ol start="3"><li>判断某个属性值是否在这个对象中 xxx in xxx</li></ol><p>注意：因为继承机制的存在，所以父类有的属性，子类也会被判定为有 如：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;toString&#x27;</span> <span class="keyword">in</span> person</span><br><span class="line">&gt; <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="string">&#x27;age&#x27;</span> <span class="keyword">in</span> person</span><br><span class="line">&gt; <span class="literal">true</span></span><br></pre></td></tr></table></figure><ol start="4"><li>判断某个属性是否在这个对象本身中 hasOwnProperty</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">person.<span class="title function_">hasOwnProperty</span>(<span class="string">&#x27;toString&#x27;</span>)</span><br><span class="line">&gt; <span class="literal">false</span></span><br><span class="line"></span><br><span class="line">person.<span class="title function_">hasOwnProperty</span>(<span class="string">&#x27;age&#x27;</span>)</span><br><span class="line">&gt; <span class="literal">true</span></span><br></pre></td></tr></table></figure><blockquote><p>注意：Map 和 Set 是 ES6 新特性</p></blockquote><br><h3 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h3><p>定义：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> map = <span class="keyword">new</span> <span class="title class_">Map</span>([[<span class="string">&#x27;tom&#x27;</span>, <span class="number">100</span>], [<span class="string">&#x27;jerry&#x27;</span>, <span class="number">99</span>]])</span><br></pre></td></tr></table></figure><p>用二维数组的形式可以直接 new 出来</p><p>元素操作：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name = map.<span class="title function_">get</span>(<span class="string">&#x27;tom&#x27;</span>) <span class="comment">//通过键获取值</span></span><br><span class="line">map.<span class="title function_">set</span>(<span class="string">&#x27;admin&#x27;</span>, <span class="number">1000</span>)    <span class="comment">//修改值，也可以增加新值</span></span><br><span class="line">map.<span class="title function_">delete</span>(<span class="string">&#x27;tom&#x27;</span>)         <span class="comment">//删除操作</span></span><br></pre></td></tr></table></figure><br><h3 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h3><p>无序不重复集合，Set 会自动进行去重操作</p><p>定义：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> set = <span class="keyword">new</span> <span class="title function_">set</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>])</span><br></pre></td></tr></table></figure><p>操作元素：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">set.<span class="title function_">add</span>(<span class="number">4</span>)    <span class="comment">//增加元素</span></span><br><span class="line">set.<span class="title function_">delete</span>(<span class="number">1</span>) <span class="comment">//删除元素</span></span><br><span class="line">set.<span class="title function_">has</span>(<span class="number">1</span>)    <span class="comment">//查找元素是否存在</span></span><br></pre></td></tr></table></figure><br><h3 id="遍历"><a href="#遍历" class="headerlink" title="遍历"></a>遍历</h3><h4 id="forEach-循环"><a href="#forEach-循环" class="headerlink" title="forEach 循环"></a>forEach 循环</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> array = [<span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>]</span><br><span class="line">array.<span class="title function_">forEach</span>(<span class="keyword">function</span>(<span class="params">value</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(value)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><br><h4 id="iterator-迭代器"><a href="#iterator-迭代器" class="headerlink" title="iterator 迭代器"></a>iterator 迭代器</h4><p>遍历数组：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> array = [<span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>]</span><br><span class="line"><span class="comment">//遍历下标，输出结果为 0 1 2</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">in</span> array) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(i)</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;==========&quot;</span>)</span><br><span class="line"><span class="comment">//遍历数组的值，输出结果为 5 6 7</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> array) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>遍历 Map 和 Set：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> map = <span class="keyword">new</span> <span class="title class_">Map</span>([[<span class="string">&#x27;Tom&#x27;</span>, <span class="number">100</span>], [<span class="string">&#x27;Jerry&#x27;</span>, <span class="number">99</span>]])</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> map) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(i)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> set = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> set) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><h3 id="变量转换"><a href="#变量转换" class="headerlink" title="变量转换"></a>变量转换</h3><blockquote><p>通过 typeof 变量名 可以输出变量的类型</p></blockquote><ol><li>String 转数字：</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>();<span class="comment">//转为整数</span></span><br><span class="line"><span class="built_in">parseFloat</span>();<span class="comment">//转为浮点数</span></span><br></pre></td></tr></table></figure><ol start="2"><li>强制类型转换</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Boolean</span>(value);<span class="comment">//把给定的值转换成Boolean型；</span></span><br><span class="line"><span class="title class_">Number</span>(value);<span class="comment">//把给定的值转换成数字（可以是整数或浮点数）；</span></span><br><span class="line"><span class="title class_">String</span>(value);<span class="comment">//把给定的值转换成字符串。</span></span><br></pre></td></tr></table></figure><blockquote><p>注意：用这三个函数之一转换值，将创建一个新值，存放由原始值直接转换成的值。这可能会造成意想不到的后果。</p></blockquote><br><h3 id="逻辑运算符"><a href="#逻辑运算符" class="headerlink" title="逻辑运算符"></a>逻辑运算符</h3><p>与 &amp;&amp;      或 ||      非！</p><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></pre></td><td class="code"><pre><span class="line">=      <span class="comment">//赋值运算符</span></span><br><span class="line">==     <span class="comment">//等于（类型不一样，值一样，也会为 true）</span></span><br><span class="line">===    <span class="comment">//绝对等于（必须类型一样，值也一样，结果才为 true）</span></span><br></pre></td></tr></table></figure><p>注意：</p><p>NaN 与任何数值都不相等，包括自己</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_">NaN</span> === <span class="title class_">NaN</span>      <span class="comment">//false</span></span><br></pre></td></tr></table></figure><p>只能通过 isNaN(NaN) 这个方法来判断一个数是否为 NaN</p><br><h2 id="JS-常用输入输出方法"><a href="#JS-常用输入输出方法" class="headerlink" title="JS 常用输入输出方法"></a>JS 常用输入输出方法</h2><table><thead><tr><th>方法名</th><th>方法的作用</th><th>参数解释</th></tr></thead><tbody><tr><td>alert(msg)</td><td>浏览器弹出带有信息的警示框</td><td>msg:要显示的信息</td></tr><tr><td>console.log(meg)</td><td>浏览器控制台打印信息</td><td>msg:要打印的信息</td></tr><tr><td>console.dir(v)</td><td>控制台打印元素对象，从而查看里面的属性和方法</td><td>v:变量名</td></tr><tr><td>prompt(msg)</td><td>浏览器弹出带有一段消息的输入框，获取输入</td><td>msg:显示消息，返回值:用户输入内容</td></tr><tr><td>confirm(msg)</td><td>浏览器弹出带有一段消息的确认框</td><td>msg:显示消息，返回值:bool类型用户是否确认</td></tr></tbody></table><br><h2 id="DOM-基础"><a href="#DOM-基础" class="headerlink" title="DOM 基础"></a>DOM 基础</h2><h3 id="基本操作"><a href="#基本操作" class="headerlink" title="基本操作"></a>基本操作</h3><blockquote><p>关于 dom 的基操，主要内容有 创建、增、删、改、查、属性操作、事件操作</p></blockquote><ol><li>创建</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="property">write</span></span><br><span class="line">innerHTML</span><br><span class="line">createElement</span><br></pre></td></tr></table></figure><ol start="2"><li>增</li></ol><figure class="highlight js"><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">appendChild</span><br><span class="line">insertBefore</span><br></pre></td></tr></table></figure><ol start="3"><li>删</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">removeChild</span><br></pre></td></tr></table></figure><ol start="4"><li>改</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">主要修改 dom 的元素属性，dom 元素的内容、属性，表单的值等</span><br><span class="line">1、修改元素属性：src、href、title 等</span><br><span class="line">2、修改普通元素内容：innerHTML、innerText</span><br><span class="line">3、修改表单元素：value、type、disable 等</span><br><span class="line">4、修改元素样式：style、className</span><br></pre></td></tr></table></figure><ol start="5"><li>查</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">主要获取查询 dom 的元素</span><br><span class="line">1、DOM 提供的 API 方法：getElementById,getElementByTagName  古老用法 不推荐</span><br><span class="line">2、H5提供的新方法：querySelector,querySelectorAll</span><br><span class="line">3、利用节点操作获取元素：父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)</span><br></pre></td></tr></table></figure><ol start="6"><li>属性操作</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">主要针对于自定义属性</span><br><span class="line">1、setAttribute</span><br><span class="line">2、getAttribute</span><br><span class="line">3、removeAttribute</span><br></pre></td></tr></table></figure><ol start="7"><li>事件操作</li></ol><p>给元素注册事件，采取 事件源.事件类型 &#x3D; 事件处理程序</p><table><thead><tr><th>鼠标事件</th><th>触发条件</th></tr></thead><tbody><tr><td>onclick</td><td>鼠标点击左键触发</td></tr><tr><td>onmouseover</td><td>鼠标经过触发</td></tr><tr><td>onmouseout</td><td>鼠标离开触发</td></tr><tr><td>onfocus</td><td>获得鼠标焦点触发</td></tr><tr><td>onblur</td><td>失去鼠标焦点触发</td></tr><tr><td>onmousemove</td><td>鼠标移动触发</td></tr><tr><td>momouseup</td><td>鼠标弹起触发</td></tr><tr><td>onmousedown</td><td>鼠标按下触发</td></tr></tbody></table><h3 id="DOM-获取元素"><a href="#DOM-获取元素" class="headerlink" title="DOM 获取元素"></a>DOM 获取元素</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementById</span>();<span class="comment">//属性名</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementByTagName</span>();<span class="comment">//标签名，如p，div，li  返回的是一个伪数组</span></span><br><span class="line">element.<span class="title function_">getElementByTagName</span>();<span class="comment">//返回element为父元素的指定标签的对象，父元素必须为单个元素</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//获取特殊元素</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>;<span class="comment">//获取body标签</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="property">documentElement</span>;<span class="comment">//获取HTML标签</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//HTML5新增 ie678不支持</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementByClassName</span>();<span class="comment">//通过类名获得对象</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">querySelector</span>();<span class="comment">//通过CSS选择器获得对象，返回指定选择器的第一个元素对象</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>();<span class="comment">//返回所有满足选择器的对象，伪数组</span></span><br></pre></td></tr></table></figure><h3 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h3><p>事件三要素：事件源、事件类型、事件处理程序</p><p>执行事件的步骤：</p><ol><li>获取事件源</li><li>注册事件（绑定事件）</li><li>添加事件处理程序（采取函数赋值形式）</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;#btn&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    btn.<span class="property">onclick</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;click事件&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>this 可以指向事件函数的调用者</p><h3 id="操作元素"><a href="#操作元素" class="headerlink" title="操作元素"></a>操作元素</h3><h4 id="改变元素的内容"><a href="#改变元素的内容" class="headerlink" title="改变元素的内容"></a>改变元素的内容</h4><figure class="highlight js"><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="property">innerText</span> = ;</span><br><span class="line">对象.<span class="property">innerHTML</span> = ;<span class="comment">//使用最多，是W3C推荐标准</span></span><br></pre></td></tr></table></figure><p>这两个属性也能读取对象内的内容</p><p>区别：</p><ul><li>innerText 不能识别 HTML 标签，innerHTML 能识别</li><li>innerText 在读取内容的时候，会自动去除空格和换行，而 innerHTML 会保留</li></ul><h4 id="操作元素属性"><a href="#操作元素属性" class="headerlink" title="操作元素属性"></a>操作元素属性</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">对象.属性名 = ;</span><br></pre></td></tr></table></figure><p>也就是可以直接修改</p><p>修改表单属性时需要用到表单特有的属性（比如要修改输入框的内容用 inner HTML 就不好使了）：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">type value checked selected disabled</span><br></pre></td></tr></table></figure><h4 id="样式属性的操作"><a href="#样式属性的操作" class="headerlink" title="样式属性的操作"></a>样式属性的操作</h4><p>通过 JS 可以修改元素的大小、颜色、位置等属性。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> element.<span class="property">style</span>          <span class="comment">//行内样式操作 如：div.style.backgroundColor = &quot;purple&quot;;</span></span><br><span class="line"><span class="number">2.</span> element.<span class="property">className</span>      <span class="comment">//类名样式操作</span></span><br></pre></td></tr></table></figure><ol><li><p>element.style</p><ul><li>属性采用的是驼峰命名法，与CSS不同，如 fontSize backgroundColor</li><li>JS 修改 style 样式时，产生的是行内样式，权重比 CSS 更高</li></ul><p> 如果要修改的样式比较少，或者功能比较简单的时候，可以这样用</p></li><li><p>element.className</p><ul><li>修改元素的类名</li><li>可以提前把要修改的内容写入 CSS 中，需要改变时应用该 CSS</li><li>会直接更改类名，也就是覆盖掉以前的类名</li><li>如果要保留以前的类名，可以在要修改的类名前加上”以前的类名 “(别忘了空格)。(其实原理就是一个元素可以又多个类名)</li></ul></li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css">    <span class="selector-tag">div</span>&#123;</span></span><br><span class="line"><span class="language-css">        <span class="attribute">width</span>: <span class="number">10px</span>;</span></span><br><span class="line"><span class="language-css">        <span class="attribute">height</span>: <span class="number">10px</span>;</span></span><br><span class="line"><span class="language-css">        <span class="attribute">background-color</span>: purple;</span></span><br><span class="line"><span class="language-css">    &#125;</span></span><br><span class="line"><span class="language-css"><span class="selector-class">.change</span>&#123;</span></span><br><span class="line"><span class="language-css">    <span class="attribute">width</span>: <span class="number">200px</span>;</span></span><br><span class="line"><span class="language-css">    <span class="attribute">height</span>: <span class="number">400px</span>;</span></span><br><span class="line"><span class="language-css">    <span class="attribute">background-color</span>: pink;</span></span><br><span class="line"><span class="language-css">    <span class="attribute">margin</span>: auto <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> div = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    div.<span class="property">onclick</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        div.<span class="property">className</span> = <span class="string">&quot;change&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="鼠标事件"><a href="#鼠标事件" class="headerlink" title="鼠标事件"></a>鼠标事件</h4><ol><li>焦点事件</li></ol><p>鼠标点击焦点事件 onfocus</p><p>失去鼠标焦点事件 onblur</p><p>(鼠标焦点是指鼠标点一下，失去焦点是指鼠标点一下其他地方)</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> input = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;input&quot;</span>);</span><br><span class="line"></span><br><span class="line">input.<span class="property">onfocus</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;得到了焦点&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">input.<span class="property">onblur</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;失去了焦点&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><ol start="2"><li>移入移出事件</li></ol><p>鼠标移入事件 onmouseover</p><p>鼠标移出事件 onmouseout</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> box = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;.box&quot;</span>);</span><br><span class="line">    box.<span class="property">onmouseover</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">style</span>.<span class="property">backgroundColor</span> = <span class="string">&quot;red&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    box.<span class="property">onmouseout</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">style</span>.<span class="property">backgroundColor</span> = <span class="string">&quot;aqua&quot;</span>;</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><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208020851505.png" alt="202112252124168"></p><h4 id="小思想-排他思想"><a href="#小思想-排他思想" class="headerlink" title="小思想-排他思想"></a>小思想-排他思想</h4><p>当用 for 循环对多个元素绑定同一事件时，如果想要某一个元素实现某个样式，则可以：</p><ol><li>清除所有元素的样式</li><li>给当前的元素设置样式</li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮1<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮2<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮3<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮4<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮5<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> btns = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;button&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; btns.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">        btns[i].<span class="property">onclick</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//先清除其他元素的格式，再给自己的元素设置格式</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">for</span> (<span class="keyword">var</span> j = <span class="number">0</span>; j &lt; btns.<span class="property">length</span>; j++) btns[j].<span class="property">style</span>.<span class="property">backgroundColor</span> = <span class="string">&quot;&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">style</span>.<span class="property">backgroundColor</span> = <span class="string">&quot;pink&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="操作自定义属性"><a href="#操作自定义属性" class="headerlink" title="操作自定义属性"></a>操作自定义属性</h4><p>元素自定义属性通常以 data- 开头，如：&lt;p data-time&#x3D;”20”&gt;&lt;&#x2F;p&gt;</p><ol><li>获取元素的属性</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">element.属性</span><br><span class="line">- 获取元素的内置属性</span><br><span class="line"></span><br><span class="line">element.getAttribute(&#x27;属性&#x27;)</span><br><span class="line">- 获取自定义属性和内置属性</span><br></pre></td></tr></table></figure><ol start="2"><li>设置元素属性</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">element.属性 = &quot;值&quot;</span><br><span class="line">element.setAttribute(&#x27;属性&#x27;, &#x27;值&#x27;)</span><br></pre></td></tr></table></figure><ol start="3"><li>移除元素属性</li></ol><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">element.removeAttribute(&#x27;属性&#x27;)</span><br></pre></td></tr></table></figure><ol start="4"><li>H5 新增获取自定义属性</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">如果有一个元素为：&lt;a data-index=&quot;1&quot;&gt;&lt;/a&gt;</span><br><span class="line"></span><br><span class="line">1. 兼容性获取：element.getArribute(&#x27;data-index&#x27;);</span><br><span class="line"></span><br><span class="line">2. H5 新增：element.dataset.index 或者 element.dataset[&#x27;index&#x27;]</span><br><span class="line">    - 只能获取 data- 开头的</span><br><span class="line">    - 开头的 data- 省略，如果后面有多个 - 连接的单词，则获取的时候采取驼峰命名法</span><br><span class="line">    - ie11 才开始支持</span><br></pre></td></tr></table></figure><h3 id="节点操作"><a href="#节点操作" class="headerlink" title="节点操作"></a>节点操作</h3><h4 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h4><p>一般的，节点至少拥有 nodeType（节点类型）、nodeName（节点名称）和 nodeValue（节点值）这三个基本属性</p><ul><li>元素节点 nodeType 为 1</li><li>属性节点 nodeType 为 2</li><li>文本节点 nodeType 为 3（文本节点包含文字，空格，换行等）</li></ul><p>节点操作的主要对象是元素节点</p><h4 id="获取父子节点"><a href="#获取父子节点" class="headerlink" title="获取父子节点"></a>获取父子节点</h4><ol><li>父级节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node.<span class="property">parentNode</span></span><br></pre></td></tr></table></figure><ul><li>parentNode 返回元素节点的<strong>最近</strong>的一个父节点（亲爸爸）</li><li>如果没有找到返回 null</li></ul><ol start="2"><li>子节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">parentNode.<span class="property">childNodes</span></span><br></pre></td></tr></table></figure><ul><li>返回值包含了元素的所有子节点，包括元素节点和文本节点</li><li>如果只想获取元素节点，则应 专门处理</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ul = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;ul&#x27;</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; ul.<span class="property">childNodes</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (ul.<span class="property">childNodes</span>[i].<span class="property">nodeType</span> === <span class="number">1</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(ul.<span class="property">childNodes</span>[i]);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>子元素节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">parentNode.<span class="property">children</span></span><br></pre></td></tr></table></figure><ul><li>children 是一个只读属性，只返回子元素节点，其余节点不返回</li><li>非标准的，但是得到了很多浏览器的支持</li></ul><ol start="4"><li>第一个&#x2F;最后一个 子节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//第一个子节点</span></span><br><span class="line">parentNode.<span class="property">firstChild</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//最后一个子节点</span></span><br><span class="line">parentNode.<span class="property">lastChild</span></span><br></pre></td></tr></table></figure><ul><li>节点包含元素节点和文本节点</li></ul><ol start="5"><li>第一个&#x2F;最后一个 子元素节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//第一个子元素节点</span></span><br><span class="line">parentNode.<span class="property">firstElementChild</span></span><br><span class="line"><span class="comment">//最后一个子元素节点</span></span><br><span class="line">parentNode.<span class="property">lastElementChild</span></span><br></pre></td></tr></table></figure><ul><li><p>这两个方法有兼容性问题，ie9 以上才支持</p></li><li><p>所以可以这样写</p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//第一个子元素节点</span></span><br><span class="line">parentNode.<span class="property">children</span>[<span class="number">0</span>]</span><br><span class="line"><span class="comment">//最后一个子元素节点</span></span><br><span class="line">parentNode.<span class="property">children</span>[parentNode.<span class="property">children</span>.<span class="property">length</span> - <span class="number">1</span>]</span><br></pre></td></tr></table></figure><h4 id="获取兄弟关系"><a href="#获取兄弟关系" class="headerlink" title="获取兄弟关系"></a>获取兄弟关系</h4><ol><li>兄弟节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//获取元素的下一个兄弟节点，包含所有节点</span></span><br><span class="line">node.<span class="property">nextSibling</span></span><br><span class="line"><span class="comment">//获取元素的上一个兄弟节点，包含所有节点</span></span><br><span class="line">node.<span class="property">previousSibling</span></span><br></pre></td></tr></table></figure><ol start="2"><li>兄弟元素节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//下一个兄弟元素节点</span></span><br><span class="line">node.<span class="property">nextElementSibling</span></span><br><span class="line"><span class="comment">//上一个兄弟元素节点</span></span><br><span class="line">node.<span class="property">previousElementSibling</span></span><br></pre></td></tr></table></figure><ul><li>兼容性问题，ie9 以上才支持</li></ul><h4 id="创建节点"><a href="#创建节点" class="headerlink" title="创建节点"></a>创建节点</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;tagName&#x27;</span>)</span><br></pre></td></tr></table></figure><ul><li>document.createElement() 方法创建由 tagName 指定的 HTML 元素。也称为动态创建元素节点</li><li>只是创建并没有添加</li></ul><h4 id="添加节点"><a href="#添加节点" class="headerlink" title="添加节点"></a>添加节点</h4><ol><li>在后面追加</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node.<span class="title function_">appendChild</span>(child)</span><br></pre></td></tr></table></figure><ul><li>将一个节点添加到指定父节点的子节点列表的末尾，类似于 css 中的 after 伪元素</li><li>也称为追加元素</li></ul><ol start="2"><li>插入节点</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node.<span class="title function_">insertBefore</span>(child, 指定元素)</span><br></pre></td></tr></table></figure><ul><li>将一个节点插入到父节点的指定子节点的前面</li></ul><h4 id="删除节点"><a href="#删除节点" class="headerlink" title="删除节点"></a>删除节点</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node.<span class="title function_">removeChild</span>(childNode)</span><br></pre></td></tr></table></figure><h4 id="复制节点"><a href="#复制节点" class="headerlink" title="复制节点"></a>复制节点</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node.<span class="title function_">cloneNode</span>()</span><br></pre></td></tr></table></figure><ul><li>克隆相当于新建，克隆后需要添加操作</li><li>如果括号参数为空或者 false，则是浅拷贝，即只克隆复制节点本身，不克隆里面的子节点</li><li>如果括号里面为 true，则是深拷贝，既复制节点本身，也复制里面的子节点</li></ul><h4 id="三种动态创建元素的区别"><a href="#三种动态创建元素的区别" class="headerlink" title="三种动态创建元素的区别"></a>三种动态创建元素的区别</h4><ul><li><p>document.write()</p><ul><li>是直接将内容写入页面的内容流，但是会导致页面全部重绘</li></ul></li><li><p>element.innerHTML</p><ul><li>是将内容写入某个 DOM 节点，不会导致页面全部重绘</li><li>创建多个元素效率更高（不要采取拼接字符串，采取数组形式拼接），结构稍微复杂</li></ul></li><li><p>document.createElement()</p><ul><li>创建多个元素效率会稍微低一些，但是结构更清晰</li></ul></li></ul><br><h2 id="DOM-高级"><a href="#DOM-高级" class="headerlink" title="DOM 高级"></a>DOM 高级</h2><h3 id="注册事件（绑定事件）"><a href="#注册事件（绑定事件）" class="headerlink" title="注册事件（绑定事件）"></a>注册事件（绑定事件）</h3><h4 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h4><ul><li>给元素添加事件，称为注册事件或者绑定事件</li><li>注册事件有两种方式：传统方式和方法监听注册方式</li></ul><ol><li>传统注册方式<ul><li>利用 on 开头的事件，如 onclick</li><li>&lt;button onclick &#x3D; “alert(‘hi’)”&gt;&lt;&#x2F;button&gt;</li><li>btn.onclick &#x3D; function() { }</li><li>特点：注册事件的唯一性</li><li>同一个元素同一个事件只能设置一个处理函数，最后注册的处理函数将会覆盖前面注册的处理函数</li></ul></li><li>方法监听注册方式<ul><li>w3c 标准推荐方式</li><li>addEventListener() 是一个方法</li><li>ie9 之前的 ie 不支持此方法，可使用 attachEvent() 代替</li><li>特点：同一个元素同一个事件可以注册多个监听器</li><li>按注册顺序依次执行</li></ul></li></ol><h4 id="addEventListener-事件监听方式"><a href="#addEventListener-事件监听方式" class="headerlink" title="addEventListener 事件监听方式"></a>addEventListener 事件监听方式</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eventTarget.<span class="title function_">addEventListener</span>(type, listener, [useCapture])</span><br></pre></td></tr></table></figure><blockquote><p>此方法会将指定的监听器注册到 eventTarget(目标对象)上，当该对象触发指定的事件时，就会执行事件处理函数</p><p>同一个元素，同一个事件可以添加多个侦听器</p></blockquote><p>该方法接收三个参数：</p><ul><li>type：事件类型<strong>字符串</strong>（别忘了加引号），比如 click, mouseover, 等，注意不用带 on</li><li>listener：事件处理函数，事件发生时，会调用该监听函数</li><li>useCapture：可选参数，是一个布尔值<ul><li>当为 true 时，事件处于捕获阶段</li><li>当为 false 或者 省略 时，事件处于冒泡阶段</li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">btn2.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">alert</span>(<span class="string">&quot;使用addEventListener添加点击事件&quot;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h4 id="attachEvent-事件监听方式（了解）"><a href="#attachEvent-事件监听方式（了解）" class="headerlink" title="attachEvent 事件监听方式（了解）"></a>attachEvent 事件监听方式（了解）</h4><blockquote><p>此方法只有 ie9 及以前的浏览器才支持，chrome 等浏览器不支持</p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eventTarget.<span class="title function_">attachEvent</span>(eventNameWithOn, callback)</span><br></pre></td></tr></table></figure><p>参数：</p><ul><li>eventTarget：目标对象</li><li>eventNameWithOn：事件类型<strong>字符串</strong>，比如 onclick, onmouseover，等，要带 on</li><li>callback：事件处理函数</li></ul><h3 id="删除事件（解绑事件）"><a href="#删除事件（解绑事件）" class="headerlink" title="删除事件（解绑事件）"></a>删除事件（解绑事件）</h3><ol><li>传统方式删除事件</li></ol><p>.onclick &#x3D; null;</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//如：想让一个div点击一下以后就不能再次点击</span></span><br><span class="line">div.<span class="property">onclick</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">alert</span>(<span class="string">&quot;111&quot;</span>);</span><br><span class="line">    div.<span class="property">onclick</span> = <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>删除方法监听注册的事件</li></ol><p>eventTarget.removeEventListener(type, listener, [useCapture])</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//如：想让一个div点击一下以后就不能再次点击</span></span><br><span class="line">div.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, fn)         <span class="comment">//fn不需要加小括号</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">alert</span>(<span class="string">&quot;222&quot;</span>)</span><br><span class="line">    div.<span class="title function_">removeEventTarget</span>(<span class="string">&quot;click&quot;</span>, fn);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>删除 attachEvent 事件</li></ol><p>eventTarget.detachEvent(eventNameWithOn, callback)</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//如：想让一个div点击一下以后就不能再次点击</span></span><br><span class="line">div.<span class="title function_">attachEvent</span>(<span class="string">&quot;onclick&quot;</span>, fn);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">alert</span>(<span class="string">&quot;333&quot;</span>)</span><br><span class="line">    div.<span class="title function_">detachEvent</span>(<span class="string">&quot;onclick&quot;</span>, fn);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="DOM-事件流"><a href="#DOM-事件流" class="headerlink" title="DOM 事件流"></a>DOM 事件流</h3><blockquote><p>事件发生时会在元素节点之间按照特定的顺序进行传播，这个传播过程叫做 DOM 事件流</p></blockquote><ul><li>JS 代码只能执行捕获或者冒泡中的一个阶段</li><li>onclick 和 attachEvent 只能得到冒泡阶段</li><li>addEventListener 的第三个参数如果为 true 表示在捕获阶段调用事件处理程序，如果为 false 或 不写则表示在冒泡阶段调用事件处理程序</li><li>有些事件是没有冒泡的，如：onblur、onfocus、onmouseenter、onmouseleave</li></ul>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="JS" scheme="https://blog.pushihao.com/tags/JS/"/>
    
    <category term="前端" scheme="https://blog.pushihao.com/tags/%E5%89%8D%E7%AB%AF/"/>
    
  </entry>
  
  <entry>
    <title>Eclipse配置Web开发环境</title>
    <link href="https://blog.pushihao.com/article/8f260c55.html"/>
    <id>https://blog.pushihao.com/article/8f260c55.html</id>
    <published>2022-08-30T02:07:41.000Z</published>
    <updated>2022-08-30T02:07:41.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>老师们似乎都倾向于使用 Eclipse 作为 Java 开发的 IDE。其实作为工具效果都是一样的，但是使用方式却不太相同。所以只能浅浅折腾一下 Eclipse 的相关配置。</p><br><h2 id="前期准备–相关软件下载"><a href="#前期准备–相关软件下载" class="headerlink" title="前期准备–相关软件下载"></a>前期准备–相关软件下载</h2><blockquote><p>注意：以下 “最新官网下载链接” 提供的均为64位windows环境下的下载链接。Linux&#x2F;Mac 请前往官网下载相对应软件</p></blockquote><table><thead><tr><th align="left">软件名</th><th>官网地址</th><th>最新版官网下载链接</th></tr></thead><tbody><tr><td align="left">Eclipse</td><td><a href="https://www.eclipse.org/">https://www.eclipse.org/</a></td><td><a href="https://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/2022-06/R/eclipse-jee-2022-06-R-win32-x86_64.zip">https://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/2022-06/R/eclipse-jee-2022-06-R-win32-x86_64.zip</a></td></tr><tr><td align="left">Oracle JDK</td><td><a href="https://www.oracle.com/">https://www.oracle.com/</a></td><td><a href="https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe">https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe</a></td></tr><tr><td align="left">Tomcat</td><td><a href="https://tomcat.apache.org/">https://tomcat.apache.org/</a></td><td><a href="https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.65/bin/apache-tomcat-9.0.65-windows-x64.zip">https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.65/bin/apache-tomcat-9.0.65-windows-x64.zip</a></td></tr><tr><td align="left">Maven</td><td><a href="https://maven.apache.org/">https://maven.apache.org/</a></td><td><a href="https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.zip">https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.zip</a></td></tr></tbody></table><br><h2 id="配置-Oracle-JDK"><a href="#配置-Oracle-JDK" class="headerlink" title="配置 Oracle JDK"></a>配置 Oracle JDK</h2><ol><li>点击 Window -&gt; Preferences -&gt; Java -&gt; Installed JREs</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301043761.png" alt="image-20220830104319669"></p><br><ol start="2"><li>点击 Add -&gt; Standard VM -&gt; Next</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301045663.png" alt="image-20220830104511607"></p><br><ol start="3"><li>点击 Directory… -&gt; 选择你的Java安装位置 -&gt; Finish</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301046690.png" alt="image-20220830104631629"></p><br><ol start="4"><li>勾选你刚配置的环境 -&gt; Apply and Close</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301047144.png" alt="image-20220830104754072"></p><p>至此，OracleJDK 环境配置完毕！</p><br><h2 id="配置-Tomcat"><a href="#配置-Tomcat" class="headerlink" title="配置 Tomcat"></a>配置 Tomcat</h2><ol><li>点击 Window -&gt; Preferences -&gt; Server -&gt; Runtime Environments -&gt; Add</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301051900.png" alt="image-20220830105148828"></p><br><ol start="2"><li>点击 Apache -&gt; Apache Tomcat v[版本号] -&gt; Next</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301053587.png" alt="image-20220830105355537"></p><br><ol start="3"><li>点击 Browse… -&gt; 选择你的 Tomcat 安装位置 -&gt; JRE勾选刚刚配置的 -&gt; Finish</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301056522.png" alt="image-20220830105608432"></p><br><ol start="4"><li>点击 Apply and Close</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301057329.png" alt="image-20220830105750264"></p><p>至此，Tomcat 的环境配置完毕！</p><br><h2 id="配置-Maven-并修改配置文件位置"><a href="#配置-Maven-并修改配置文件位置" class="headerlink" title="配置 Maven 并修改配置文件位置"></a>配置 Maven 并修改配置文件位置</h2><ol><li>点击 Window -&gt; Preferences -&gt; Maven -&gt; Installations -&gt; Add</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301100529.png" alt="image-20220830110030455"></p><br><ol start="2"><li>点击 Directory… -&gt; 选择你的Maven安装位置 -&gt; Finish</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301102522.png" alt="image-20220830110214468"></p><br><ol start="3"><li>点击 Window -&gt; Preferences -&gt; Maven -&gt; User Settings -&gt; Browse… -&gt; 选择配置文件位置 -&gt; Update Settings -&gt; Apply and Close</li></ol><blockquote><p>注意：图一图二展示了配置文件所在位置 (都在Maven安装目录下)</p></blockquote><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301106925.png" alt="image-20220830110624846"></p><p>(图一)</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301106620.png" alt="image-20220830110639564"></p><p>(图二)</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301104816.png" alt="image-20220830110422736"></p><p>至此，Maven 环境配置完毕！接下来进行<strong>验证</strong></p><br><p>验证. 点击 Window -&gt; Show View -&gt; Other… -&gt; Maven -&gt; Maven Repositories -&gt; Open</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301113587.png" alt="image-20220830111354524"></p><p>可以看到，Maven的本地仓库以及中央仓库都是配置文件中所设置的</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301114402.png" alt="image-20220830111458350"></p><br><h2 id="配置编辑器字体"><a href="#配置编辑器字体" class="headerlink" title="配置编辑器字体"></a>配置编辑器字体</h2><ol><li>点击 Window -&gt; Preferences -&gt; General -&gt; Appearance -&gt; Colors and Fonts -&gt; Java -&gt; Java Editor Text Font -&gt; Edit</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301119964.png" alt="image-20220830111938887"></p><br><ol start="2"><li>编辑字体 -&gt; 确定</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301121980.png" alt="image-20220830112140929"></p><p>至此，编辑器字体修改完成！</p><br><h2 id="配置控制台字体"><a href="#配置控制台字体" class="headerlink" title="配置控制台字体"></a>配置控制台字体</h2><ol><li>点击 Window -&gt; Preferences -&gt; General -&gt; Appearance -&gt; Colors and Fonts -&gt; Basic -&gt; Text Font -&gt; Edit</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301125787.png" alt="image-20220830112324235"></p><br><ol start="2"><li>编辑字体 -&gt; 确定</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208301125559.png" alt="image-20220830112502502"></p><p>至此，控制台字体修改完成！</p><br><p>大功告成！</p><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="配置" scheme="https://blog.pushihao.com/tags/%E9%85%8D%E7%BD%AE/"/>
    
    <category term="Eclipse" scheme="https://blog.pushihao.com/tags/Eclipse/"/>
    
    <category term="IDE" scheme="https://blog.pushihao.com/tags/IDE/"/>
    
  </entry>
  
  <entry>
    <title>Vue2 基本知识</title>
    <link href="https://blog.pushihao.com/article/139e1b0f.html"/>
    <id>https://blog.pushihao.com/article/139e1b0f.html</id>
    <published>2022-08-29T07:46:00.000Z</published>
    <updated>2022-08-29T07:46:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Vue是什么"><a href="#Vue是什么" class="headerlink" title="Vue是什么"></a>Vue是什么</h2><p>Vue (读音 &#x2F;vjuː&#x2F;，类似于 <strong>view</strong>) 是一套用于构建用户界面的<strong>渐进式框架</strong>。与其它大型框架不同的是，Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合。另一方面，当与<a href="https://v3.cn.vuejs.org/guide/single-file-component.html">现代化的工具链</a>以及各种<a href="https://github.com/vuejs/awesome-vue#components--libraries">支持类库</a>结合使用时，Vue 也完全能够为复杂的单页应用提供驱动。</p><br><h2 id="引入"><a href="#引入" class="headerlink" title="引入"></a>引入</h2><p>使用 CDN：</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></pre></td><td class="code"><pre><span class="line">开发版本：</span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line">生产版本：</span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue@2.6.14&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><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">https://cdn.jsdelivr.net/npm/vue@next/dist/</span><br><span class="line">https://unpkg.com/browse/vue@3.2.31/dist/</span><br></pre></td></tr></table></figure><br><h2 id="第一个Vue应用"><a href="#第一个Vue应用" class="headerlink" title="第一个Vue应用"></a>第一个Vue应用</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;zh&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Hello Vue<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">   <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h1</span>&gt;</span>&#123;&#123;message&#125;&#125;<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">   <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">         <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">         <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">message</span>: <span class="string">&quot;Hello&quot;</span></span></span><br><span class="line"><span class="language-javascript">         &#125;</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">   </span></span><br><span class="line"><span class="language-javascript">   </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h2 id="常用指令"><a href="#常用指令" class="headerlink" title="常用指令"></a>常用指令</h2><h3 id="插值表达式"><a href="#插值表达式" class="headerlink" title="插值表达式"></a>插值表达式</h3><figure class="highlight javascript"><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">&#123;&#123;name&#125;&#125;</span><br><span class="line">&#123;&#123;school.<span class="property">name</span>&#125;&#125;</span><br></pre></td></tr></table></figure><p>通过插值表达式可以直接在页面中使用变量的值</p><br><h3 id="v-html"><a href="#v-html" class="headerlink" title="v-html"></a>v-html</h3><p>向标签中插入一段html代码</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-html</span>=<span class="string">&quot;strong&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">strong</span>: <span class="string">&#x27;&lt;b&gt;strong&lt;/b&gt;&#x27;</span></span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-text"><a href="#v-text" class="headerlink" title="v-text"></a>v-text</h3><p>向标签中插入一段纯文本</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">v-text</span>=<span class="string">&quot;message&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--等同于--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;message&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-for"><a href="#v-for" class="headerlink" title="v-for"></a>v-for</h3><p>循环指令，用于遍历数组等，在遍历数组时还可以加上index获取下标</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-for</span>=<span class="string">&quot;(item, index) in items&quot;</span>&gt;</span></span><br><span class="line">        &#123;&#123;item.name&#125;&#125; ===&gt; &#123;&#123;index&#125;&#125;</span><br><span class="line">    <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">items</span>: [</span></span><br><span class="line"><span class="language-javascript">                &#123;<span class="attr">name</span>: <span class="string">&quot;Pillage&quot;</span>&#125;,</span></span><br><span class="line"><span class="language-javascript">                &#123;<span class="attr">name</span>: <span class="string">&quot;Daisy&quot;</span>&#125;,</span></span><br><span class="line"><span class="language-javascript">                &#123;<span class="attr">name</span>: <span class="string">&quot;Steven&quot;</span>&#125;</span></span><br><span class="line"><span class="language-javascript">            ]</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-if"><a href="#v-if" class="headerlink" title="v-if"></a>v-if</h3><p>条件语句，可以结合使用 v-else v-else-if，值为布尔类型</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-if</span>=<span class="string">&quot;flag&quot;</span>&gt;</span>Yes<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-else</span>&gt;</span>No<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   </span><br><span class="line">   ===================================</span><br><span class="line">   </span><br><span class="line">   <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-if</span>=<span class="string">&quot;tag == &#x27;A&#x27;&quot;</span>&gt;</span>A<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-else-if</span>=<span class="string">&quot;tag == &#x27;B&#x27;&quot;</span>&gt;</span>B<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-else-if</span>=<span class="string">&quot;tag == &#x27;C&#x27;&quot;</span>&gt;</span>C<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-else</span>&gt;</span>D<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">   </span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">   <span class="keyword">var</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">         <span class="attr">flag</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="language-javascript">         </span></span><br><span class="line"><span class="language-javascript">         <span class="attr">tag</span>: <span class="string">&quot;A&quot;</span></span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">   &#125;);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-show"><a href="#v-show" class="headerlink" title="v-show"></a>v-show</h3><p>根据判断条件来决定是否展示该标签</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-show</span>=<span class="string">&quot;show&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">h1</span>&gt;</span>展示<span class="tag">&lt;/<span class="name">h1</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-show</span>=<span class="string">&quot;notShow&quot;</span>&gt;</span>未展示<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">show</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">notShow</span>: <span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-bind"><a href="#v-bind" class="headerlink" title="v-bind"></a>v-bind</h3><p>为属性绑定一个值或变量</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">a</span> <span class="attr">v-bind:href</span>=<span class="string">&quot;hao123&quot;</span>&gt;</span>hao123<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">hao123</span>: <span class="string">&#x27;https://www.hao123.com/&#x27;</span></span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>此指令具有简写形式（v-bind: 可以简写为 :）</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">v-bind:href</span>=<span class="string">&quot;hao123&quot;</span>&gt;</span>hao123<span class="tag">&lt;/<span class="name">a</span>&gt;</span>      =&gt;      <span class="tag">&lt;<span class="name">a</span> <span class="attr">:href</span>=<span class="string">&quot;hao123&quot;</span>&gt;</span>hao123<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-on"><a href="#v-on" class="headerlink" title="v-on"></a>v-on</h3><p>为标签绑定事件</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">button</span> <span class="attr">v-on:click</span>=<span class="string">&quot;click&quot;</span>&gt;</span>Click Me<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">   <span class="keyword">var</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">         <span class="attr">message</span>: <span class="string">&quot;pillage&quot;</span></span></span><br><span class="line"><span class="language-javascript">      &#125;,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">         <span class="attr">click</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="title function_">alert</span>(<span class="variable language_">this</span>.<span class="property">message</span>)</span></span><br><span class="line"><span class="language-javascript">         &#125;</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">   &#125;);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>修饰符 (modifier) 是以半角句号 <code>.</code> 指明的特殊后缀，用于指出一个指令应该以特殊方式绑定。例如，<code>.prevent</code> 修饰符告诉 <code>v-on</code> 指令对于触发的事件调用 <code>event.preventDefault()</code>：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">v-on:submit.prevent</span>=<span class="string">&quot;onSubmit&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure><br><p>此指令也具有简写形式（v-on: 可以简写为 @）</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">v-on:click</span>=<span class="string">&quot;click&quot;</span>&gt;</span>Click Me<span class="tag">&lt;/<span class="name">button</span>&gt;</span>   =&gt;   </span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;click&quot;</span>&gt;</span>Click Me<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-model"><a href="#v-model" class="headerlink" title="v-model"></a>v-model</h3><p>v-model可以实现对数据的双向绑定</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">   输入一段文字：</span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;message&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">   您输入的文字为：&#123;&#123;message&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">   <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">         <span class="attr">message</span>: <span class="string">&quot;&quot;</span></span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">   &#125;);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-once"><a href="#v-once" class="headerlink" title="v-once"></a>v-once</h3><p>仅加载一次数据，以后数据即使改变也不会影响</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>姓名为：<span class="tag">&lt;<span class="name">span</span> <span class="attr">v-once</span>&gt;</span>&#123;&#123;name&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;changeName&quot;</span>&gt;</span>修改姓名<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">name</span>: <span class="string">&#x27;pillage&#x27;</span></span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="title function_">changeName</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;小白&#x27;</span></span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h3 id="v-cloak"><a href="#v-cloak" class="headerlink" title="v-cloak"></a>v-cloak</h3><p>当 Vue 实例编译结束，页面渲染后，此属性会立刻消失</p><p>作用：可以用来解决网速慢时页面出现一堆  的情况</p><p>基本使用：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css">    <span class="selector-attr">[v-cloak]</span> &#123;</span></span><br><span class="line"><span class="language-css">        <span class="attribute">display</span>: none;</span></span><br><span class="line"><span class="language-css">    &#125;</span></span><br><span class="line"><span class="language-css"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span> <span class="attr">v-cloak</span>&gt;</span></span><br><span class="line">    &#123;&#123;info.name&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><br><br><h2 id="计算属性和侦听器"><a href="#计算属性和侦听器" class="headerlink" title="计算属性和侦听器"></a>计算属性和侦听器</h2><h3 id="计算属性"><a href="#计算属性" class="headerlink" title="计算属性"></a>计算属性</h3><p>计算属性使用了缓存机制，所以它执行的效率要比 methods 方法要高</p><p>计算属性也有两种写法：</p><ol><li>类似于函数的简写形式</li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    &#123;&#123;date&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">computed</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="title function_">date</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span> <span class="title class_">Date</span>.<span class="title function_">now</span>()</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>这样写默认只有getter方法，没有setter方法</p><br><ol start="2"><li>对象形式</li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    &#123;&#123;name&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">currentName</span>: <span class="string">&#x27;pillage&#x27;</span></span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">computed</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">name</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">get</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">currentName</span></span></span><br><span class="line"><span class="language-javascript">                &#125;,</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">set</span>(<span class="params">newValue</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">currentName</span> = newValue</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>此时运行 <code>vm.name = &#39;小白&#39;</code> 时，setter 会被自动调用，currentName 的值被更新</p><br><br><h3 id="侦听器"><a href="#侦听器" class="headerlink" title="侦听器"></a>侦听器</h3><p>虽然计算属性在大多数情况下更合适，但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 <code>watch</code> 选项提供了一个更通用的方法，来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时，这个方式是最有用的。</p><p>他也有两种写法（简写形式和对象形式）</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><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="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">v-text</span>=<span class="string">&quot;university&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123;person&#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">university</span>: <span class="string">&quot;东北林业大学&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">person</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">name</span>: <span class="string">&quot;pillage&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">age</span>: <span class="number">19</span></span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//watch 监听</span></span></span><br><span class="line"><span class="language-javascript">        <span class="attr">watch</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//监听university属性值,newValue代表新值,oldValue代表旧值</span></span></span><br><span class="line"><span class="language-javascript">            <span class="title function_">university</span>(<span class="params">newValue, oldValue</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;newValue:&quot;</span> + newValue + <span class="string">&quot;  oldValue:&quot;</span> + oldValue)</span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//监听person对象的值，对象的监控只能获取新值</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">person</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//开启深度监控；监控对象中的属性值变化</span></span></span><br><span class="line"><span class="language-javascript">                <span class="attr">deep</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//获取到对象的最新属性数据(obj代表新对象)</span></span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">handler</span>(<span class="params">obj</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;name:&quot;</span> + obj.<span class="property">name</span> + <span class="string">&quot;  age:&quot;</span> + obj.<span class="property">age</span>)</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">    &#125;);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h2 id="基本使用：收集表单数据"><a href="#基本使用：收集表单数据" class="headerlink" title="基本使用：收集表单数据"></a>基本使用：收集表单数据</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">        账号：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;account&quot;</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        密码：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;password&quot;</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        性别：</span><br><span class="line">        男<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;sex&quot;</span> <span class="attr">value</span>=<span class="string">&quot;boy&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;sex&quot;</span>&gt;</span></span><br><span class="line">        女<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;sex&quot;</span> <span class="attr">value</span>=<span class="string">&quot;girl&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;sex&quot;</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        爱好：</span><br><span class="line">        敲代码<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">value</span>=<span class="string">&quot;code&quot;</span> <span class="attr">name</span>=<span class="string">&quot;hobby&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;hobby&quot;</span>&gt;</span></span><br><span class="line">        吃包子<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">value</span>=<span class="string">&quot;eat&quot;</span> <span class="attr">name</span>=<span class="string">&quot;hobby&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;hobby&quot;</span>&gt;</span></span><br><span class="line">        刷视频<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">value</span>=<span class="string">&quot;video&quot;</span> <span class="attr">name</span>=<span class="string">&quot;hobby&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;hobby&quot;</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        所在省份：</span><br><span class="line">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">name</span>=<span class="string">&quot;province&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;province&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>&gt;</span>请选择<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;henan&quot;</span>&gt;</span>河南<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;tianjin&quot;</span>&gt;</span>天津<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;beijing&quot;</span>&gt;</span>北京<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;chongqing&quot;</span>&gt;</span>重庆<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        其他信息：</span><br><span class="line">        <span class="tag">&lt;<span class="name">textarea</span> <span class="attr">v-model</span>=<span class="string">&quot;other&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">textarea</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;accept&quot;</span>&gt;</span>我已阅读并接受<span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;&quot;</span>&gt;</span>《隐私声明》<span class="tag">&lt;/<span class="name">a</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">button</span>&gt;</span>提交<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">account</span>: <span class="string">&#x27;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">password</span>: <span class="string">&#x27;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">sex</span>: <span class="string">&#x27;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">hobby</span>: [],</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">province</span>: <span class="string">&#x27;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">other</span>: <span class="string">&#x27;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">accept</span>: <span class="literal">false</span>,</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h2 id="生命周期钩子"><a href="#生命周期钩子" class="headerlink" title="生命周期钩子"></a>生命周期钩子</h2><p>如下图：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202206101257712.jpeg" alt="img"> </p><p>(图片来源于网络)</p><p>其中 mounted 最常用，常用于发送 ajax 请求获取数据</p><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="前端" scheme="https://blog.pushihao.com/tags/%E5%89%8D%E7%AB%AF/"/>
    
    <category term="vue" scheme="https://blog.pushihao.com/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>Ribbon 简单使用</title>
    <link href="https://blog.pushihao.com/article/29faa60e.html"/>
    <id>https://blog.pushihao.com/article/29faa60e.html</id>
    <published>2022-08-21T00:31:00.000Z</published>
    <updated>2022-08-21T00:31:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是负载均衡"><a href="#什么是负载均衡" class="headerlink" title="什么是负载均衡"></a>什么是负载均衡</h2><p><strong>负载均衡</strong>（load balancing）是一种电子计算机技术，用来在多个计算机（计算机集群）、网络连接、CPU、磁盘驱动器或其他资源中分配负载，以达到优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。 使用带有负载均衡的多个服务器组件，取代单一的组件，可以通过冗余提高可靠性。负载均衡服务通常是由专用软件和硬件来完成。主要作用是将大量作业合理地分摊到多个操作单元上进行执行，用于解决互联网架构中的高并发和高可用的问题。</p><p>简单来说，就是将所有请求先集中在一起，然后再根据特定的算法将这些请求分配出去，使各个服务器的效率都能最大化。</p><p>常见的负载均衡算法有：</p><ul><li>随机法(Random)</li><li>加权随机法(Weight Random)</li><li>轮询法(Round Robin)</li><li>加权轮询法(Weight Round Robin)</li><li>平滑加权轮询法(Smooth Weight Round Robin)</li><li>地址哈希法(Hash)</li><li>最小连接数法(Least Connections)</li></ul><br><h2 id="Ribbon-简介"><a href="#Ribbon-简介" class="headerlink" title="Ribbon 简介"></a>Ribbon 简介</h2><p>Ribbon 是一个由 Netflix 创建并开源（目前已闭源）的<strong>客户端</strong>负载均衡器。</p><br><h2 id="使用-Ribbon"><a href="#使用-Ribbon" class="headerlink" title="使用 Ribbon"></a>使用 Ribbon</h2><h3 id="导入-Ribbon"><a href="#导入-Ribbon" class="headerlink" title="导入 Ribbon"></a>导入 Ribbon</h3><p>由于 Nacos 注册与发现中心已默认集成了 Ribbon，因此我们不必再手动导入。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208201045610.png" alt="image-20220820104543533"></p><br><h3 id="Ribbon-负载均衡策略"><a href="#Ribbon-负载均衡策略" class="headerlink" title="Ribbon 负载均衡策略"></a>Ribbon 负载均衡策略</h3><p>各负载均衡策略的关系继承图如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208201056590.png" alt="image-20220820105620540"></p><p>主要提供了如下几种负载均衡策略</p><table><thead><tr><th>名称</th><th>策略解释</th></tr></thead><tbody><tr><td>RoundRobinRule</td><td>轮询策略</td></tr><tr><td>WeightedResponseTimeRule</td><td>服务实例的平均响应时间越短则权重越大，那么服务实例被选中执行的概率也就越大</td></tr><tr><td>RandomRule</td><td>随机策略</td></tr><tr><td>RetryRule</td><td>在轮询的基础上进行重试（超过重试时间服务实例仍无效则进行轮询）</td></tr><tr><td>NacosRule</td><td>根据Nacos设置的权重进行挑选</td></tr><tr><td>ClientConfigEnabledRoundRobinRule</td><td>和RoundRobinRule一致，轮询策略</td></tr><tr><td>BestAvailableRule</td><td>过滤掉失效的服务实例然后找出并发请求最小的服务实例进行使用</td></tr><tr><td>AvailabilityFilteringRule</td><td>先过滤掉故障实例然后选择并发较小的服务实例</td></tr><tr><td>ZoneAvoidanceRule</td><td><strong>默认负载均衡策略</strong>。根据判断server所在区域的性能和server的可用性来过滤服务实例。过滤成功后，使用轮询策略从过滤结果中选择服务实例</td></tr></tbody></table><br><h3 id="使用-Ribbon-默认负载均衡策略"><a href="#使用-Ribbon-默认负载均衡策略" class="headerlink" title="使用 Ribbon 默认负载均衡策略"></a>使用 Ribbon 默认负载均衡策略</h3><p>只需要在 RestTemplate Bean类上添加一个 @LoadBalanced 注解即可使用 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><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><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> com.pushihao.orderRibbon.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.client.RestTemplateBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.loadbalancer.LoadBalanced;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RestConfig</span> &#123;</span><br><span class="line"></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">(RestTemplateBuilder builder)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> builder.build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><h3 id="修改-Ribbon-负载均衡策略"><a href="#修改-Ribbon-负载均衡策略" class="headerlink" title="修改 Ribbon 负载均衡策略"></a>修改 Ribbon 负载均衡策略</h3><ol><li>通过配置类进行修改</li></ol><blockquote><p>注意：配置类不能放在 @SpringBootApplication 注解的 @ComponentScan 能扫描到的地方</p></blockquote><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208201200488.png" alt="image-20220820120034423"> </p><p>RibbonRandomRuleConfig.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><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> com.pushihao.ribbon;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.netflix.loadbalancer.IRule;</span><br><span class="line"><span class="keyword">import</span> com.netflix.loadbalancer.RandomRule;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RibbonRandomRuleConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//注意：方法名一定叫 iRule</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> IRule <span class="title function_">iRule</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><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>RestConfig.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.orderRibbon.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.client.RestTemplateBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.loadbalancer.LoadBalanced;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.ribbon.RibbonClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.ribbon.RibbonClients;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"><span class="keyword">import</span> com.pushihao.ribbon.RibbonRandomRuleConfig;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@RibbonClients(value = &#123;</span></span><br><span class="line"><span class="meta">        @RibbonClient(name = &quot;stock-service&quot;, configuration = RibbonRandomRuleConfig.class)</span></span><br><span class="line"><span class="meta">&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RestConfig</span> &#123;</span><br><span class="line"></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">(RestTemplateBuilder builder)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> builder.build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><ol start="2"><li>通过配置文件进行修改</li></ol><p>application.yml</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></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">9002</span></span><br><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">nacos:</span></span><br><span class="line">      <span class="attr">server-addr:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8848</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">order-service</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 第一行是服务名，负载均衡策略配置的值为类的全路径</span></span><br><span class="line"><span class="attr">stock-service:</span></span><br><span class="line">  <span class="attr">ribbon:</span></span><br><span class="line">    <span class="attr">NFLoadBalancerRuleClassName:</span> <span class="string">com.alibaba.cloud.nacos.ribbon.NacosRule</span></span><br></pre></td></tr></table></figure><br><h3 id="自定义负载均衡策略"><a href="#自定义负载均衡策略" class="headerlink" title="自定义负载均衡策略"></a>自定义负载均衡策略</h3><p>通过实现 IRule 接口或继承 AbstractLoadBalancerRule 抽象类可以自定义负载均衡策略，主要的逻辑代码在 choose 方法中。</p><p>比如我要自己实现一个随机策略的负载均衡器</p><p>CustomRuleConfig.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.ribbon;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.netflix.client.config.IClientConfig;</span><br><span class="line"><span class="keyword">import</span> com.netflix.loadbalancer.AbstractLoadBalancerRule;</span><br><span class="line"><span class="keyword">import</span> com.netflix.loadbalancer.ILoadBalancer;</span><br><span class="line"><span class="keyword">import</span> com.netflix.loadbalancer.IRule;</span><br><span class="line"><span class="keyword">import</span> com.netflix.loadbalancer.Server;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ThreadLocalRandom;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomRuleConfig</span> <span class="keyword">extends</span> <span class="title class_">AbstractLoadBalancerRule</span> &#123;</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="comment">//获得当前请求的服务的实例</span></span><br><span class="line">        <span class="type">ILoadBalancer</span> <span class="variable">loadBalancer</span> <span class="operator">=</span> <span class="built_in">this</span>.getLoadBalancer();</span><br><span class="line">        List&lt;Server&gt; reachableServers = loadBalancer.getReachableServers();</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">randomNum</span> <span class="operator">=</span> ThreadLocalRandom.current().nextInt(reachableServers.size());</span><br><span class="line"></span><br><span class="line">        <span class="type">Server</span> <span class="variable">server</span> <span class="operator">=</span> reachableServers.get(randomNum);</span><br><span class="line">        <span class="keyword">if</span> (server.isAlive()) &#123;</span><br><span class="line">            <span class="keyword">return</span> server;</span><br><span class="line">        &#125; <span class="keyword">else</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">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">initWithNiwsConfig</span><span class="params">(IClientConfig iClientConfig)</span> &#123; &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后通过配置类或配置文件修改使用自己的负载均衡策略，例如</p><p>application.yml</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">stock-service:</span></span><br><span class="line">  <span class="attr">ribbon:</span></span><br><span class="line">    <span class="attr">NFLoadBalancerRuleClassName:</span> <span class="string">com.pushihao.ribbon.CustomRuleConfig</span></span><br></pre></td></tr></table></figure><br><h3 id="配置-Ribbon-负载均衡预加载"><a href="#配置-Ribbon-负载均衡预加载" class="headerlink" title="配置 Ribbon 负载均衡预加载"></a>配置 Ribbon 负载均衡预加载</h3><p>Ribbon 的负载均衡器默认是懒加载，也就是当第一次访问时才会加载，那么就会导致第一次访问时间较长甚至出现网络连接超时的情况。我们可以通过开启预加载（启动服务时就加载）来解决这个问题。</p><p>application.yml</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#预加载配置,默认为懒加载</span></span><br><span class="line"><span class="attr">ribbon:</span></span><br><span class="line">  <span class="attr">eager-load:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span></span><br><span class="line">    <span class="comment"># 需要开启预加载的服务名</span></span><br><span class="line">    <span class="attr">clients:</span> <span class="string">stock-service1,stock-service2</span></span><br></pre></td></tr></table></figure><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="微服务" scheme="https://blog.pushihao.com/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"/>
    
    <category term="SpringCloud" scheme="https://blog.pushihao.com/tags/SpringCloud/"/>
    
    <category term="负载均衡" scheme="https://blog.pushihao.com/tags/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/"/>
    
  </entry>
  
  <entry>
    <title>Nacos 简单使用</title>
    <link href="https://blog.pushihao.com/article/2ec54589.html"/>
    <id>https://blog.pushihao.com/article/2ec54589.html</id>
    <published>2022-08-20T01:15:00.000Z</published>
    <updated>2022-08-20T01:15:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Nacos-是什么"><a href="#Nacos-是什么" class="headerlink" title="Nacos 是什么"></a>Nacos 是什么</h2><p><strong>Nacos</strong>（Naming and Configuration Service）是阿里巴巴的一个开源项目，也是 Spring Cloud Alibaba 的一个重要组件。专注于服务发现和配置管理领域。</p><p><a href="https://nacos.io/zh-cn/docs/what-is-nacos.html">Nacos 官方文档</a></p><blockquote><p>注意：如果中途发现操作过程一样但还是报错，很有可能是版本号不一致（新版本不一定兼容老版本）。</p></blockquote><br><h2 id="部署-Nacos-服务器"><a href="#部署-Nacos-服务器" class="headerlink" title="部署 Nacos 服务器"></a>部署 Nacos 服务器</h2><p>Nacos 作为 Spring Cloud Alibaba 的一个组件，版本号自然也一定要选择正确，参考 <a href="https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E">官方版本说明</a></p><table><thead><tr><th>Spring Cloud Alibaba Version</th><th>Sentinel Version</th><th>Nacos Version</th><th>RocketMQ Version</th><th>Dubbo Version</th><th>Seata Version</th></tr></thead><tbody><tr><td>2021.0.1.0*</td><td>1.8.3</td><td>1.4.2</td><td>4.9.2</td><td>2.7.15</td><td>1.4.2</td></tr><tr><td>2.2.7.RELEASE</td><td>1.8.1</td><td>2.0.3</td><td>4.6.1</td><td>2.7.13</td><td>1.3.0</td></tr><tr><td>2.2.6.RELEASE</td><td>1.8.1</td><td>1.4.2</td><td>4.4.0</td><td>2.7.8</td><td>1.3.0</td></tr><tr><td>2021.1 or 2.2.5.RELEASE or 2.1.4.RELEASE or 2.0.4.RELEASE</td><td>1.8.0</td><td>1.4.1</td><td>4.4.0</td><td>2.7.8</td><td>1.3.0</td></tr><tr><td>2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE</td><td>1.8.0</td><td>1.3.3</td><td>4.4.0</td><td>2.7.8</td><td>1.3.0</td></tr><tr><td>2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE</td><td>1.7.1</td><td>1.2.1</td><td>4.4.0</td><td>2.7.6</td><td>1.2.0</td></tr><tr><td>2.2.0.RELEASE</td><td>1.7.1</td><td>1.1.4</td><td>4.4.0</td><td>2.7.4.1</td><td>1.0.0</td></tr><tr><td>2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE</td><td>1.7.0</td><td>1.1.4</td><td>4.4.0</td><td>2.7.3</td><td>0.9.0</td></tr><tr><td>2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE</td><td>1.6.3</td><td>1.1.1</td><td>4.4.0</td><td>2.7.3</td><td>0.7.1</td></tr></tbody></table><p>Nacos 软件直接上 GitHub 下载即可，项目地址为 <a href="https://github.com/alibaba/nacos/releases">Releases · alibaba&#x2F;nacos (github.com)</a></p><p>下载完毕后解压，进入 bin 目录，然后运行单机模式</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sh startup.sh -m standalone  //Linux</span><br><span class="line">bash startup.sh -m standalone  //Ubuntu</span><br><span class="line"></span><br><span class="line">startup.cmd -m standalone  //Windows</span><br></pre></td></tr></table></figure><br><p>启动成功后，浏览器输入 <a href="http://localhost:8848/nacos">http://localhost:8848/nacos</a> 即可打开 Nacos 管理面板，账号和密码默认都是 nacos</p><br><br><h2 id="搭建-Nacos-客户端"><a href="#搭建-Nacos-客户端" class="headerlink" title="搭建 Nacos 客户端"></a>搭建 Nacos 客户端</h2><p>由于 Spring Cloud Alibaba 版本控制器中默认集成了 Nacos，所以在导入时不需要提供版本号</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="comment">&lt;!--导入Nacos注册与发现中心--&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-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></pre></td></tr></table></figure><br><h4 id="修改-application-yml-配置文件"><a href="#修改-application-yml-配置文件" class="headerlink" title="修改 application.yml 配置文件"></a>修改 application.yml 配置文件</h4><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></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">9002</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="attr">name:</span> <span class="string">stock-service</span>  <span class="comment">#模块名</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">server-addr:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8848</span>  <span class="comment">#nacos地址</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">username:</span> <span class="string">nacos</span>  <span class="comment">#用户名</span></span><br><span class="line">        <span class="attr">password:</span> <span class="string">nacos</span>  <span class="comment">#密码</span></span><br><span class="line">        <span class="attr">namespace:</span> <span class="string">public</span>  <span class="comment">#命名空间</span></span><br></pre></td></tr></table></figure><p>当有了此配置后，当服务启动时就会自动注册进入 Nacos 注册中心</p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205172135693.png" alt="image-20220517213516550"  /> <h4 id="增加配置类"><a href="#增加配置类" class="headerlink" title="增加配置类"></a>增加配置类</h4><p>当有<strong>消费者</strong>要调用注册中心的服务时，必须配置一个负载均衡策略，Spring Cloud Alibaba 默认的负载均衡器是 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_">RestConfig</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">(RestTemplateBuilder restTemplateBuilder)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> restTemplateBuilder.build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>此时就可以通过服务名调用 Nacos 注册中心中已经注册的服务了</p><br><h4 id="在-controller-中调用注册中心的模块"><a href="#在-controller-中调用注册中心的模块" class="headerlink" title="在 controller 中调用注册中心的模块"></a>在 controller 中调用注册中心的模块</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/order&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;add&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;下单成功&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">String</span> <span class="variable">msg</span> <span class="operator">=</span> restTemplate.getForObject(<span class="string">&quot;http://stock-service/stock/reduct&quot;</span>, String.class);  <span class="comment">//注意此处不是ip地址，是服务名</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;下单成功&lt;hr/&gt;&quot;</span> + msg;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>至此，Nacos-Client 环境搭建成功</p><br><br><h2 id="Nacos-配置参数"><a href="#Nacos-配置参数" class="headerlink" title="Nacos 配置参数"></a>Nacos 配置参数</h2><p>Nacos 参数的配置主要在 application.yml 中进行，文档可参考 <a href="https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery">Nacos-discovery&#x2F;wiki</a>，主要配置项如下：</p><table><thead><tr><th>配置项</th><th>Key</th><th>默认值</th><th>说明</th></tr></thead><tbody><tr><td>服务端地址</td><td><code>spring.cloud.nacos.discovery.server-addr</code></td><td>无</td><td>Nacos Server 启动监听的ip地址和端口</td></tr><tr><td>服务名</td><td><code>spring.cloud.nacos.discovery.service</code></td><td>${spring.application.name}</td><td>给当前的服务命名</td></tr><tr><td>服务分组</td><td><code>spring.cloud.nacos.discovery.group</code></td><td>DEFAULT_GROUP</td><td>设置服务所处的分组</td></tr><tr><td>权重</td><td><code>spring.cloud.nacos.discovery.weight</code></td><td>1</td><td>取值范围 1 到 100，数值越大，权重越大</td></tr><tr><td>网卡名</td><td><code>spring.cloud.nacos.discovery.network-interface</code></td><td>无</td><td>当IP未配置时，注册的IP为此网卡所对应的IP地址，如果此项也未配置，则默认取第一块网卡的地址</td></tr><tr><td>注册的IP地址</td><td><code>spring.cloud.nacos.discovery.ip</code></td><td>无</td><td>优先级最高</td></tr><tr><td>注册的端口</td><td><code>spring.cloud.nacos.discovery.port</code></td><td>-1</td><td>默认情况下不用配置，会自动探测</td></tr><tr><td>命名空间</td><td><code>spring.cloud.nacos.discovery.namespace</code></td><td>无</td><td>常用场景之一是不同环境的注册的区分隔离，例如开发测试环境和生产环境的资源（如配置、服务）隔离等。</td></tr><tr><td>AccessKey</td><td><code>spring.cloud.nacos.discovery.access-key</code></td><td>无</td><td>当要上阿里云时，阿里云上面的一个云账号名</td></tr><tr><td>SecretKey</td><td><code>spring.cloud.nacos.discovery.secret-key</code></td><td>无</td><td>当要上阿里云时，阿里云上面的一个云账号密码</td></tr><tr><td>Metadata</td><td><code>spring.cloud.nacos.discovery.metadata</code></td><td>无</td><td>使用Map格式配置，用户可以根据自己的需要自定义一些和服务相关的元数据信息</td></tr><tr><td>日志文件名</td><td><code>spring.cloud.nacos.discovery.log-name</code></td><td>无</td><td></td></tr><tr><td>集群</td><td><code>spring.cloud.nacos.discovery.cluster-name</code></td><td>DEFAULT</td><td>配置成Nacos集群名称</td></tr><tr><td>接入点</td><td><code>spring.cloud.nacos.discovery.enpoint</code></td><td>UTF-8</td><td>地域的某个服务的入口域名，通过此域名可以动态地拿到服务端地址</td></tr><tr><td>是否集成Ribbon</td><td><code>ribbon.nacos.enabled</code></td><td>true</td><td>一般都设置成true即可</td></tr><tr><td>是否开启Nacos Watch</td><td><code>spring.cloud.nacos.discovery.watch.enabled</code></td><td>true</td><td>可以设置成false来关闭 watch</td></tr></tbody></table><br><br><h2 id="Nacos-集群部署"><a href="#Nacos-集群部署" class="headerlink" title="Nacos 集群部署"></a>Nacos 集群部署</h2><p>之前使用的 <code>./startup.sh -m standalone</code> 命令就是以单机模式启动 nacos 服务器。但是当我们用到微服务架构时，往往是项目规模达到了一定的程度。所以在真正使用的时候，大部分情况下都是以集群方式进行部署的，<a href="https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html">参考文档</a></p><br><h4 id="下载若干个-nacos-服务器"><a href="#下载若干个-nacos-服务器" class="headerlink" title="下载若干个 nacos 服务器"></a>下载若干个 nacos 服务器</h4><p>这里以三个为例，给他们重命名，建议在名字后面加上端口号方便区分：</p><blockquote><p>注意：单机集群启动的时候<strong>不能使用连续的端口</strong>了，会报错</p></blockquote><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208191120477.png" alt="image-20220819112031363"> </p><br><h4 id="修改-application-properties-配置文件"><a href="#修改-application-properties-配置文件" class="headerlink" title="修改 application.properties 配置文件"></a>修改 application.properties 配置文件</h4><p>在这一步需要配置数据源为 MySQL，因为 Nacos 内部使用的数据源 Hikari。我们要想搭建集群，就必须使用同一数据源（类似于 Scrapy 的分布式爬虫）</p><p>如下配置：</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><span class="line">6</span><br><span class="line">7</span><br><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">#*************** Config Module Related Configurations ***************#</span></span><br><span class="line"><span class="comment">### If use MySQL as datasource:</span></span><br><span class="line"><span class="attr">spring.datasource.platform</span>=<span class="string">mysql</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">### Count of DB:</span></span><br><span class="line"><span class="attr">db.num</span>=<span class="string">1</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">### Connect URL of DB:</span></span><br><span class="line"><span class="attr">db.url.0</span>=<span class="string">jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&amp;connectTimeout=1000&amp;socketTimeout=3000&amp;autoReconnect=true&amp;useUnicode=true&amp;useSSL=false&amp;serverTimezone=UTC</span></span><br><span class="line"><span class="attr">db.user.0</span>=<span class="string">root</span></span><br><span class="line"><span class="attr">db.password.0</span>=<span class="string">Pu2003..</span></span><br></pre></td></tr></table></figure><br><p>修改三个 nacos 的端口：</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">### Default web server port:</span></span><br><span class="line"><span class="attr">server.port</span>=<span class="string">[8840/8850/8860]</span></span><br></pre></td></tr></table></figure><br><h4 id="修改-cluster-conf-example"><a href="#修改-cluster-conf-example" class="headerlink" title="修改 cluster.conf.example"></a>修改 cluster.conf.example</h4><blockquote><p>先将其复制一份为 cluster.conf，然后再进行修改</p></blockquote><p>主要就是添加 nacos 集群节点</p><p>例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#it is ip</span><br><span class="line">#example</span><br><span class="line">192.168.0.108:8849</span><br><span class="line">192.168.0.108:8850</span><br><span class="line">192.168.0.108:8851</span><br></pre></td></tr></table></figure><br><h4 id="创建-MySQL-数据库"><a href="#创建-MySQL-数据库" class="headerlink" title="创建 MySQL 数据库"></a>创建 MySQL 数据库</h4><p>按照其要求创建 MySQL 数据库，并执行他所提供的 sql 文件（nacos-mysql.sql）</p><p>执行完之后表结构大致如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205202127134.png" alt="image-20220520212757077">  </p><br><h4 id="修改项目-application-yml-文件"><a href="#修改项目-application-yml-文件" class="headerlink" title="修改项目 application.yml 文件"></a>修改项目 application.yml 文件</h4><p>官方推荐集群部署后使用VIP或者域名访问，不过也可以使用直连模式：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></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">nacos:</span></span><br><span class="line">      <span class="attr">server-addr:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8840,</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8850,</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8860</span></span><br></pre></td></tr></table></figure><p>至此，就实现了 Nacos 的集群部署。接下来，我们也可以使用负载均衡软件如 Nginx 来进行集群的负载均衡。</p><br><h4 id="使用-nginx-进行反向代理"><a href="#使用-nginx-进行反向代理" class="headerlink" title="使用 nginx 进行反向代理"></a>使用 nginx 进行反向代理</h4><p>修改 &#x2F;etc&#x2F;nginx&#x2F;nginx.conf 文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"># Nacos</span><br><span class="line">upstream nacoscluster &#123;</span><br><span class="line">    server 127.0.0.1:8840;</span><br><span class="line">    server 127.0.0.1:8850;</span><br><span class="line">    server 127.0.0.1:8860;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">server &#123;</span><br><span class="line">    listen8847;</span><br><span class="line">    server_namelocalhost;</span><br><span class="line"></span><br><span class="line">    location /nacos/&#123;</span><br><span class="line">    proxy_passhttp://nacoscluster/nacos/;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>启动所有 nacos 服务器，并启动 nginx，理论上打开浏览器 <a href="http://localhost:8847/nacos">http://localhost:8847/nacos</a></p><p>登录后即可看到如下效果：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208191217504.png" alt="image-20220819121740445"> </p><p>nginx 默认的负载均衡机制是轮询方式，所以理论上请求时就会在三台服务器之间来回跳</p><br><p>至此，Nacos 集群环境就搭建好了，修改项目的 Nacos 地址配置文件：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></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">nacos:</span></span><br><span class="line">          <span class="attr">server-addr:</span> <span class="number">192.168</span><span class="number">.220</span><span class="number">.1</span><span class="string">:8847</span></span><br></pre></td></tr></table></figure><p>启动对应服务，OK，<strong>日常报错</strong>：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205202229686.png" alt="image-20220520222915533"> </p><br><p>查看官方文档，发现 2.x 版本和 1.x 版本还不太一样：</p><p>Nacos2.0版本相比1.X新增了gRPC的通信方式，因此需要增加2个端口。新增端口是在配置的主端口(server.port)基础上，进行一定偏移量自动生成。</p><table><thead><tr><th>端口</th><th>与主端口的偏移量</th><th>描述</th></tr></thead><tbody><tr><td>9847</td><td>1000</td><td>客户端gRPC请求服务端端口，用于客户端向服务端发起连接和请求</td></tr><tr><td>9848</td><td>1001</td><td>服务端gRPC请求服务端端口，用于服务间同步等</td></tr></tbody></table><p>使用VIP&#x2F;nginx请求时，需要配置成<strong>TCP转发</strong>，不能配置http2转发，否则连接会被nginx断开。</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205202239313.png" alt="nacos"></p><p>（图片来源于网络，侵删）</p><blockquote><p>注意：使用 Nginx 配置 tcp 转发时需要用到 stream 模块，而 Nginx 在安装时是默认不编译 stream 模块的，需要我们手动安装</p></blockquote><p>成功安装之后查看：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208191147135.png" alt="image-20220819114704082"></p><br><p>接下来配置 nginx 的 tcp 转发：</p><ul><li>修改 nginx.conf，在最后一行加上 <code>include /usr/local/nginx/tcp.d/*.conf;</code>，注意不要写在 http 里</li><li>新建 &#x2F;usr&#x2F;local&#x2F;nginx&#x2F;tcp.d&#x2F;tcp.conf</li><li>编辑 tcp.conf 文件</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"># tcp.conf</span><br><span class="line"></span><br><span class="line">stream &#123;</span><br><span class="line"></span><br><span class="line"># Nacos集群配置grpc</span><br><span class="line">    upstream nacoscluster &#123;</span><br><span class="line">  server 127.0.0.1:9840;</span><br><span class="line">  server 127.0.0.1:9850;</span><br><span class="line">  server 127.0.0.1:9860;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  server &#123;</span><br><span class="line">  listen9847;</span><br><span class="line">  proxy_passnacoscluster;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>修改项目的 Nacos 地址配置文件：</li></ul><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></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">nacos:</span></span><br><span class="line">          <span class="attr">server-addr:</span> <span class="number">192.168</span><span class="number">.220</span><span class="number">.1</span><span class="string">:8847</span></span><br></pre></td></tr></table></figure><br><p>启动服务，完成！</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="微服务" scheme="https://blog.pushihao.com/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"/>
    
    <category term="SpringCloud" scheme="https://blog.pushihao.com/tags/SpringCloud/"/>
    
  </entry>
  
  <entry>
    <title>Spring Cloud Alibaba 环境搭建</title>
    <link href="https://blog.pushihao.com/article/3555320b.html"/>
    <id>https://blog.pushihao.com/article/3555320b.html</id>
    <published>2022-08-19T10:20:00.000Z</published>
    <updated>2022-08-19T10:20:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="微服务概述"><a href="#微服务概述" class="headerlink" title="微服务概述"></a>微服务概述</h2><p><strong>微服务</strong>（Microservices）是一种<strong>软件架构风格</strong>，它是以专注于单一责任与功能的小型功能区块（Small Building Blocks）为基础，利用模块化的方式组合出复杂的大型应用程序，各功能区块使用与语言无关 (Language-Independent&#x2F;Language agnostic）的<a href="https://zh.wikipedia.org/wiki/%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%8E%A5%E5%8F%A3">API</a>集相互通信。</p><p>简单来说，就是将一整套服务流程拆分成更小的模块，每个模块各司其职。各个模块之间通过 HTTP API 进行通信。</p><br><h2 id="Spring-Cloud-概述"><a href="#Spring-Cloud-概述" class="headerlink" title="Spring Cloud 概述"></a>Spring Cloud 概述</h2><p>Spring Cloud 为开发者提供了工具来快速构建分布式系统中的一些常见模式（例如配置管理、服务注册与发现、熔断器、智能路由等）。Spring Cloud 可以使开发人员更快速地开发实现这些模式的服务和应用程序。它们在任何分布式环境中都能很好地工作，包括开发人员自己的笔记本电脑、裸机数据中心以及 Cloud Foundry 等托管平台。</p><p>简单来说，Spring Cloud 是 Spring 为微服务架构提供的<strong>一整套</strong>的<strong>解决方案</strong>。而 Spring Cloud Alibaba 是国内阿里巴巴团队自研发的一套解决方案。</p><br><h2 id="分布式环境搭建"><a href="#分布式环境搭建" class="headerlink" title="分布式环境搭建"></a>分布式环境搭建</h2><blockquote><p>说明：可以手动从一个 Maven 项目进行搭建，后期也可以利用 Idea 工具直接从阿里云官网进行快捷搭建，网址为<a href="https://start.aliyun.com/bootstrap.html">Aliyun Java Initializr</a>，类似于 SpringBoot 的初始化向导 <a href="https://start.spring.io/">Spring Initializr</a></p></blockquote><h4 id="创建父级-Spring-Boot-项目"><a href="#创建父级-Spring-Boot-项目" class="headerlink" title="创建父级 Spring Boot 项目"></a>创建父级 Spring Boot 项目</h4><p>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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--parent中使用的版本管理器一般是自己公司内部的版本管理器，对于第三方的版本管理器一般放在dependencyManagement中--&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.pushihao<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>test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>test<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">description</span>&gt;</span>test<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>11<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">spring.boot.version</span>&gt;</span>2.6.7<span class="tag">&lt;/<span class="name">spring.boot.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">            <span class="comment">&lt;!--spring-boot版本管理器--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;spring.boot.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><br><h4 id="新建两个模块"><a href="#新建两个模块" class="headerlink" title="新建两个模块"></a>新建两个模块</h4><blockquote><p>新建子模块时最好新建 Maven 项目，因为可以设置父项目。如果新建 Spring Boot Initializr 则默认父项目是 spring-boot-starter-parent</p></blockquote><p>这里以订单模块（order）和仓库模块（stock）为例</p><p>假设仓库模块为生产者，订单模块为调用者。当调用订单模块时，订单模块调用仓库模块，使库存减一</p><p>项目结构如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151418396.png" alt="image-20220515141833219"> </p><br><p>具体文件：</p><p>pom.xml （两个模块的 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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>SpringCloud<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.pushihao<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--此处为stock或order(模块名)--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>stock<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-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">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><br><p>StockApplication.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StockApplication</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(StockApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>StockController.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><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> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/stock&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StockController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;reduct&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">reduct</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;库存减一&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>OrderApplication.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><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">package</span> com.pushihao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.client.RestTemplateBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderApplication</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(OrderApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">(RestTemplateBuilder builder)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> builder.build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>OrderController.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/order&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;add&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;订单加一&quot;</span>);</span><br><span class="line">        <span class="comment">//result为返回结果</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> restTemplate.getForObject(<span class="string">&quot;http://localhost:9001/stock/reduct&quot;</span>, String.class);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><p>至此，一个简单的分布式环境就搭建好了，使用浏览器调用  <a href="http://localhost:9002/order/add">http://localhost:9002/order/add</a> 就可以看到结果</p><p> <img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151424602.png" alt="image-20220515142425523"> </p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151425477.png" alt="image-20220515142503403"> </p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151425474.png" alt="image-20220515142533403"></p><br><br><br><h2 id="Spring-Cloud-Alibaba-环境搭建"><a href="#Spring-Cloud-Alibaba-环境搭建" class="headerlink" title="Spring Cloud Alibaba 环境搭建"></a>Spring Cloud Alibaba 环境搭建</h2><p>可以直接在原有的分布式环境上直接引用 Spring Cloud Alibaba 即可</p><p>项目结构如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151451100.png" alt="image-20220515145136915"> </p><br><h4 id="导入-Spring-Cloud-Alibaba-和-Spring-Cloud-的坐标"><a href="#导入-Spring-Cloud-Alibaba-和-Spring-Cloud-的坐标" class="headerlink" title="导入 Spring Cloud Alibaba 和 Spring Cloud 的坐标"></a>导入 Spring Cloud Alibaba 和 Spring Cloud 的坐标</h4><blockquote><p>注意：版本号一定要选对（按照要求）参考 <a href="https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E">版本说明</a></p></blockquote><p>稳定版本依赖关系</p><table><thead><tr><th>Spring Cloud Alibaba Version</th><th>Spring Cloud Version</th><th>Spring Boot Version</th></tr></thead><tbody><tr><td>2021.0.1.0</td><td>Spring Cloud 2021.0.1</td><td>2.6.3</td></tr><tr><td>2.2.7.RELEASE</td><td>Spring Cloud Hoxton.SR12</td><td>2.3.12.RELEASE</td></tr><tr><td>2021.1</td><td>Spring Cloud 2020.0.1</td><td>2.4.2</td></tr><tr><td>2.2.6.RELEASE</td><td>Spring Cloud Hoxton.SR9</td><td>2.3.2.RELEASE</td></tr><tr><td>2.1.4.RELEASE</td><td>Spring Cloud Greenwich.SR6</td><td>2.1.13.RELEASE</td></tr><tr><td>2.2.1.RELEASE</td><td>Spring Cloud Hoxton.SR3</td><td>2.2.5.RELEASE</td></tr><tr><td>2.2.0.RELEASE</td><td>Spring Cloud Hoxton.RELEASE</td><td>2.2.X.RELEASE</td></tr><tr><td>2.1.2.RELEASE</td><td>Spring Cloud Greenwich</td><td>2.1.X.RELEASE</td></tr><tr><td>2.0.4.RELEASE(停止维护，建议升级)</td><td>Spring Cloud Finchley</td><td>2.0.X.RELEASE</td></tr><tr><td>1.5.1.RELEASE(停止维护，建议升级)</td><td>Spring Cloud Edgware</td><td>1.5.X.RELEASE</td></tr></tbody></table><br><p>组件版本关系（一般由Spring Cloud Alibaba 版本管理器直接控制，我们不用关心）</p><table><thead><tr><th>Spring Cloud Alibaba Version</th><th>Sentinel Version</th><th>Nacos Version</th><th>RocketMQ Version</th><th>Dubbo Version</th><th>Seata Version</th></tr></thead><tbody><tr><td>2021.0.1.0*</td><td>1.8.3</td><td>1.4.2</td><td>4.9.2</td><td>2.7.15</td><td>1.4.2</td></tr><tr><td>2.2.7.RELEASE</td><td>1.8.1</td><td>2.0.3</td><td>4.6.1</td><td>2.7.13</td><td>1.3.0</td></tr><tr><td>2.2.6.RELEASE</td><td>1.8.1</td><td>1.4.2</td><td>4.4.0</td><td>2.7.8</td><td>1.3.0</td></tr><tr><td>2021.1 or 2.2.5.RELEASE or 2.1.4.RELEASE or 2.0.4.RELEASE</td><td>1.8.0</td><td>1.4.1</td><td>4.4.0</td><td>2.7.8</td><td>1.3.0</td></tr><tr><td>2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE</td><td>1.8.0</td><td>1.3.3</td><td>4.4.0</td><td>2.7.8</td><td>1.3.0</td></tr><tr><td>2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE</td><td>1.7.1</td><td>1.2.1</td><td>4.4.0</td><td>2.7.6</td><td>1.2.0</td></tr><tr><td>2.2.0.RELEASE</td><td>1.7.1</td><td>1.1.4</td><td>4.4.0</td><td>2.7.4.1</td><td>1.0.0</td></tr><tr><td>2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE</td><td>1.7.0</td><td>1.1.4</td><td>4.4.0</td><td>2.7.3</td><td>0.9.0</td></tr><tr><td>2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE</td><td>1.6.3</td><td>1.1.1</td><td>4.4.0</td><td>2.7.3</td><td>0.7.1</td></tr></tbody></table><br><p>这里使用最新稳定版即可</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--parent中使用的版本管理器一般是自己公司内部的版本管理器，对于第三方的版本管理器一般放在dependencyManagement中--&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.pushihao<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>test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modules</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>order<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>stock<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>order-nacos<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>stock-nacos<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">modules</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>test<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">description</span>&gt;</span>test<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>11<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">spring.boot.version</span>&gt;</span>2.3.12.RELEASE<span class="tag">&lt;/<span class="name">spring.boot.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">spring.cloud.version</span>&gt;</span>Hoxton.SR12<span class="tag">&lt;/<span class="name">spring.cloud.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">spring.cloud.alibaba.version</span>&gt;</span>2.2.7.RELEASE<span class="tag">&lt;/<span class="name">spring.cloud.alibaba.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"></span><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><br><span class="line">            <span class="comment">&lt;!--spring-boot版本管理器--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;spring.boot.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">            <span class="comment">&lt;!--spring-cloud版本管理器--&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>$&#123;spring.cloud.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">            <span class="comment">&lt;!--spring-cloud-alibaba版本管理器--&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>$&#123;spring.cloud.alibaba.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><br><br><h4 id="新建-stock-nacos-模块"><a href="#新建-stock-nacos-模块" class="headerlink" title="新建 stock-nacos 模块"></a>新建 stock-nacos 模块</h4><p>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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>SpringCloud<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.pushihao<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>stock-nacos<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-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><br><span class="line"><span class="comment">&lt;!--注册与发现--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.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-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><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.8.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">source</span>&gt;</span>11<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">target</span>&gt;</span>11<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><br><p>application.yml</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></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">9001</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="attr">name:</span> <span class="string">stock-service</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">server-addr:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8848</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">username:</span> <span class="string">nacos</span></span><br><span class="line">        <span class="attr">password:</span> <span class="string">nacos</span></span><br><span class="line">        <span class="attr">cluster-name:</span> <span class="string">public</span></span><br></pre></td></tr></table></figure><br><p>StockNacosApplication.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StockNacosApplication</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(StockNacosApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>StockController.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><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> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/stock&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StockController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;reduct&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">reduct</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;库存减一&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="新建-order-nacos-模块"><a href="#新建-order-nacos-模块" class="headerlink" title="新建 order-nacos 模块"></a>新建 order-nacos 模块</h4><p>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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.pushihao<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>order-nacos<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-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><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-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><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.8.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">source</span>&gt;</span>11<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">target</span>&gt;</span>11<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><br><p>application.yml</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></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">9001</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="attr">name:</span> <span class="string">order-service</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">server-addr:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8848</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">username:</span> <span class="string">nacos</span></span><br><span class="line">        <span class="attr">password:</span> <span class="string">nacos</span></span><br><span class="line">        <span class="attr">namespace:</span> <span class="string">public</span></span><br><span class="line">        <span class="comment"># ephemeral: false  #是否是临时实例 默认是true（临时实例）  永久实例：哪怕宕机了也不会删除实例</span></span><br></pre></td></tr></table></figure><br><p>OrderNacosApplication.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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">package</span> com.pushihao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.client.RestTemplateBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.loadbalancer.LoadBalanced;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderNacosApplication</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(OrderNacosApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//加上@LoadBalanced就配上了默认的负载均衡器Ribbon</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">(RestTemplateBuilder restTemplateBuilder)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> restTemplateBuilder.build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>OrderController.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.pushihao.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/order&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;add&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;下单成功&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//这里就可以把域名替换成对应的服务名，调用时就会启用默认的负载均衡机制</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">msg</span> <span class="operator">=</span> restTemplate.getForObject(<span class="string">&quot;http://stock-service/stock/reduct&quot;</span>, String.class);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><p>至此 Spring Cloud Alibaba 环境就搭建完毕了</p><p>依次启动 nacos 服务器、stock-nacos、order-nacos</p><br><p>浏览器输入 <a href="http://localhost:8848/nacos">http://localhost:8848/nacos</a> 在服务管理一栏即可查看注册的微服务</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151510938.png" alt="image-20220515151008799"> </p><br><p>浏览器输入 <a href="http://localhost:9001/order/add">http://localhost:9001/order/add</a> 即可查看运行结果</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151511190.png" alt="image-20220515151112093"> </p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151511209.png" alt="image-20220515151132121"> </p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151511421.png" alt="image-20220515151145336"></p><br><p>成功！</p><br><br><h2 id="使用-Aliyun-Java-Initializr-快速构建"><a href="#使用-Aliyun-Java-Initializr-快速构建" class="headerlink" title="使用 Aliyun Java Initializr 快速构建"></a>使用 Aliyun Java Initializr 快速构建</h2><p>可以直接在网页上 <a href="https://start.aliyun.com/bootstrap.html">Aliyun Java Initializr</a> 进行配置，然后下载初始代码并导入编辑器工具中</p><p>不过更多情况下，都是使用 Idea 工具进行快速构建，如下：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202205151515070.png" alt="image-20220515151549955"> </p><br><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="环境搭建" scheme="https://blog.pushihao.com/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    
    <category term="微服务" scheme="https://blog.pushihao.com/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"/>
    
    <category term="SpringCloud" scheme="https://blog.pushihao.com/tags/SpringCloud/"/>
    
  </entry>
  
  <entry>
    <title>什么是RSS？什么是Feed？它们有什么关系？</title>
    <link href="https://blog.pushihao.com/article/f45e8b82.html"/>
    <id>https://blog.pushihao.com/article/f45e8b82.html</id>
    <published>2022-08-18T01:17:00.000Z</published>
    <updated>2022-08-18T01:17:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是RSS？"><a href="#什么是RSS？" class="headerlink" title="什么是RSS？"></a>什么是RSS？</h2><p><strong>RSS</strong>（英文全称：RDF Site Summary 或 Really Simple Syndication），可以翻译为“简易信息聚合”或“聚合内容”，<strong>是一种消息来源格式规范</strong>，用以聚合多个网站更新的内容并自动通知网站订阅者。将文章标题、摘要、内容按照用户需求推送给用户便是RSS的目的。</p><p>RSS 的第一个版本为 RDF Site Summary，在1999年三月由美国网景公司的 Guha 为了用在My.Netscape.Com 门户网站而开发。在 Netscape 放弃该标准后，软件制造商 UserLand 开始着手开发。随着 2002 年 RSS 2.0.1 规范的发布，UserLand 冻结了该标准并将版权转让给哈佛大学的伯克曼互联网与社会中心。Web社区对进一步发展的渴望导致了另一种称为 Atom 的联合标准的创建。</p><blockquote><p>总结：RSS 和 Atom 其实就是一种提供消息来源的格式规范。Atom 是在 RSS 的基础上发展而来的，弥补了 RSS 的一些不足。他们本质上都是供机器阅读的 xml 文件，订阅者可以通过 RSS 阅读器阅读文章内容。</p></blockquote><br><h2 id="什么是Feed？它和RSS有什么关系？"><a href="#什么是Feed？它和RSS有什么关系？" class="headerlink" title="什么是Feed？它和RSS有什么关系？"></a>什么是Feed？它和RSS有什么关系？</h2><p><strong>Feed</strong>（英语：<strong>web feed</strong>、<strong>news feed</strong>、<strong>syndicated feed</strong>），中文可以译为<strong>消息来源</strong>，是一种<strong>资料格式</strong>，网站可以透过它将最新文章或者消息传播给订阅者。常用的 Feed 格式有 RSS、Atom 两种，有些网站也会同时提供两种格式的订阅链接。Feed常常被博客以及新闻网站广泛应用。普通用户可以通过客户端软件订阅Feed地址，这类软件一般被称为聚合器、RSS阅读器、Feed阅读器等。</p><p>网站中通常以<img class="inline-img" src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208181138466.svg" style="height:17px" />或<img class="inline-img" src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208181010543.svg" style="height:17px" />图标为 Feed 地址标识。</p><blockquote><p>总结：Feed 是一种资料格式，常用的有 RSS 和 Atom 两种规范。用户可以通过阅读器软件订阅 Feed 获取网站的最新消息。</p></blockquote>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="技术杂谈" scheme="https://blog.pushihao.com/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/"/>
    
    
    <category term="RSS" scheme="https://blog.pushihao.com/tags/RSS/"/>
    
    <category term="Feed" scheme="https://blog.pushihao.com/tags/Feed/"/>
    
    <category term="Atom" scheme="https://blog.pushihao.com/tags/Atom/"/>
    
  </entry>
  
  <entry>
    <title>Docker基本使用</title>
    <link href="https://blog.pushihao.com/article/ced71d50.html"/>
    <id>https://blog.pushihao.com/article/ced71d50.html</id>
    <published>2022-08-15T12:55:00.000Z</published>
    <updated>2024-10-16T00:36:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是-docker"><a href="#什么是-docker" class="headerlink" title="什么是 docker"></a>什么是 docker</h2><p>作为一个开源的应用容器引擎，docker主要用于开发和运行应用。docker容器和虚拟机有些类似，但二者在原理上不同。容器是将操作系统层虚拟化，而虚拟机则是虚拟化硬件。因此容器相较于虚拟机来说更加便携、轻量以及高效。</p><p>所以我们可以简单的将docker容器理解为一个轻量版的虚拟机。在docker之上我们可以高效地运行各式各样的应用，应用之间相互独立而又可以互相协调。</p><br><h2 id="docker组成"><a href="#docker组成" class="headerlink" title="docker组成"></a>docker组成</h2><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202208160900332.png" alt="Docker"></p><p>其中，容器和镜像的概念一定要分清。他俩的关系就像是Java中的类与对象。镜像是一个只读模板，用于指示创建容器，而容器是镜像的可运行实例。一个镜像也可以创建很多个容器，这些容器可以相互独立运行。</p><p>Docker注册中心(Docker registry)也被称为Docker仓库，主要用于存储docker镜像。Docker Hub是一个公共的注册中心，任何人都可以在此处下载镜像。</p><br><h2 id="docker基本常用命令"><a href="#docker基本常用命令" class="headerlink" title="docker基本常用命令"></a>docker基本常用命令</h2><h3 id="镜像相关"><a href="#镜像相关" class="headerlink" title="镜像相关"></a>镜像相关</h3><ol><li>检索镜像</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker search [关键字]</span><br></pre></td></tr></table></figure><ol start="2"><li>获取镜像(默认从Docker Hub下载)</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]</span><br></pre></td></tr></table></figure><ol start="3"><li>列出镜像</li></ol><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">docker image <span class="built_in">ls</span></span><br><span class="line">docker images</span><br></pre></td></tr></table></figure><ol start="4"><li>导入镜像</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker load [文件]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 举例：docker load &lt; image.tar</span></span><br></pre></td></tr></table></figure><ol start="5"><li>导出镜像</li></ol><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">docker save [镜像名/镜像ID] [输出]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 举例：docker save 0fdf2b4c26d3 &gt; image.tar</span></span><br><span class="line"><span class="comment"># 也可以将多个image打包成一个文件：docker save -o images.tar postgres:9.6 mongo:3.4</span></span><br></pre></td></tr></table></figure><ol start="6"><li>删除镜像</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker rmi [镜像ID]</span><br></pre></td></tr></table></figure><h3 id="容器相关"><a href="#容器相关" class="headerlink" title="容器相关"></a>容器相关</h3><ol><li>启动容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建并启动容器</span></span><br><span class="line">docker run [选项] [镜像名/镜像ID[:TAG]] [命令] [参数]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动目前终止的容器</span></span><br><span class="line">docker start [容器名/容器ID]</span><br></pre></td></tr></table></figure><p><code>docker run</code>常用选项：</p><ul><li><strong>-d:</strong> 后台运行容器</li><li><strong>-i:</strong> 以交互模式运行容器，通常与 -t 同时使用；</li><li><strong>-P:</strong> 随机端口映射，容器内部端口<strong>随机</strong>映射到主机的端口</li><li><strong>-p:</strong> 指定端口映射，格式为：<strong>主机(宿主)端口:容器端口</strong></li><li><strong>-t:</strong> 为容器重新分配一个伪输入终端，通常与 -i 同时使用</li><li><strong>–name</strong>: 为容器指定一个名称</li><li><strong>-e:</strong> 设置环境变量</li><li><strong>–env-file:</strong> 从指定文件读入环境变量</li><li><strong>–net:</strong> 指定容器的网络连接类型</li><li><strong>–link:</strong> 添加链接到另一个容器</li><li><strong>–expose:</strong> 开放一个端口或一组端口</li><li><strong>–volume, -v:</strong> 绑定一个卷，将本地文件夹与容器文件夹共享</li></ul><p>举例：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker run -it -p 80:80 -p 443:443 --name lnmp -v ~/docker/lnmp/data:/root/data centos:7 /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="comment"># 以bash为交互方式运行一个centos7容器，放行80和443端口，取名为lnmp，并将本机（宿主机）的 ~/docker/lnmp/data 目录与容器内的 /root/data 目录绑定</span></span><br></pre></td></tr></table></figure><ol start="2"><li>查看容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看正在运行的容器</span></span><br><span class="line">docker ps</span><br><span class="line"></span><br><span class="line"><span class="comment">#　查看所有容器</span></span><br><span class="line">docker ps -a</span><br></pre></td></tr></table></figure><ol start="3"><li>终止容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stop [容器名/容器ID]</span><br></pre></td></tr></table></figure><ol start="5"><li>重启容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker restart [容器名/容器ID]</span><br></pre></td></tr></table></figure><ol start="6"><li>进入容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 退出后容器终止</span></span><br><span class="line">docker attach [容器名/容器ID]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 退出后容器正常运行</span></span><br><span class="line">docker <span class="built_in">exec</span> -it [容器名/容器ID] /bin/bash</span><br></pre></td></tr></table></figure><ol start="7"><li>导入容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker import [选项] [文件路径/URL] [REPOSITORY[:TAG]]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 举例：docker import ./myredis.tar.gz myredis:1</span></span><br></pre></td></tr></table></figure><ol start="8"><li>导出容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">export</span> [容器名/容器ID] [输出]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 举例：docker export myredis &gt; myredis.tar.gz</span></span><br></pre></td></tr></table></figure><blockquote><p>注：用户既可以使用 <code>docker load</code> 来导入镜像存储文件到本地镜像库，也可以使用 <code>docker import</code> 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息（即仅保存容器当时的快照状态），而镜像存储文件将保存完整记录，体积也要大。此外，从容器快照文件导入时可以重新指定标签等元数据信息。</p></blockquote><ol start="9"><li>删除容器</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">rm</span> [容器ID/容器名]</span><br></pre></td></tr></table></figure><ol start="10"><li>复制文件</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 从主机复制到容器</span></span><br><span class="line">docker <span class="built_in">cp</span> [主机路径] [容器ID]:[容器路径]</span><br><span class="line"><span class="comment"># 从容器复制到主机</span></span><br><span class="line">docker <span class="built_in">cp</span> [容器ID]:[容器路径] [主机路径]</span><br></pre></td></tr></table></figure><br><br><p><strong>参考：</strong></p><p>【1】：<a href="https://zh.wikipedia.org/wiki/Docker#">Docker - 维基百科</a></p><p>【2】：<a href="https://www.runoob.com/docker/docker-tutorial.html">Docker 教程 | 菜鸟教程</a></p><p>【3】：<a href="https://yeasy.gitbook.io/docker_practice/">Docker - 从入门到实践</a></p><p>【4】：<a href="https://docs.docker.com/engine/">Docker Engine overview | Docker Documentation</a></p><p>【5】：<a href="https://www.hangge.com/blog/cache/detail_2411.html">Docker - 实现本地镜像的导出、导入(export、import、save、load)</a></p><p>【6】：<a href="https://cloud.tencent.com/developer/article/1772136">一张脑图整理Docker常用命令 - 腾讯云开发者社区</a></p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="Docker" scheme="https://blog.pushihao.com/tags/Docker/"/>
    
    <category term="容器" scheme="https://blog.pushihao.com/tags/%E5%AE%B9%E5%99%A8/"/>
    
  </entry>
  
  <entry>
    <title>TensorFlow启用GPU加速</title>
    <link href="https://blog.pushihao.com/article/fd161a70.html"/>
    <id>https://blog.pushihao.com/article/fd161a70.html</id>
    <published>2022-07-07T03:57:00.000Z</published>
    <updated>2022-07-07T03:57:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>据官网介绍，对于 tensorflow1.15 及更早版本，CPU和GPU软件包是分开的。</p><figure class="highlight powershell"><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">pip install tensorflow==<span class="number">1.15</span>      <span class="comment"># CPU</span></span><br><span class="line">pip install tensorflow<span class="literal">-gpu</span>==<span class="number">1.15</span>  <span class="comment"># GPU</span></span><br></pre></td></tr></table></figure><p>而之后的版本，我们可以直接在CPU版本的基础上开启GPU加速。</p><p>参考：<a href="https://www.tensorflow.org/install/gpu">GPU支持 | TensorFlow</a> (tensorflow官方网站，国内访问可能较慢)</p><br><h2 id="安装TensorFlow最新版"><a href="#安装TensorFlow最新版" class="headerlink" title="安装TensorFlow最新版"></a>安装TensorFlow最新版</h2><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install tensorflow</span><br></pre></td></tr></table></figure><p>如果嫌弃安装速度太慢，也可以使用国内豆瓣源</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install tensorflow <span class="literal">-i</span> https://pypi.doubanio.com/simple/</span><br></pre></td></tr></table></figure><br><h2 id="启用GPU加速"><a href="#启用GPU加速" class="headerlink" title="启用GPU加速"></a>启用GPU加速</h2><h3 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h3><ol><li>硬件要求</li></ol><p>支持以下带有 GPU 的设备：</p><ul><li>CUDA® 架构为 3.5、5.0、6.0、7.0、7.5、8.0 或更高的 NVIDIA® GPU 卡。请参阅<a href="https://developer.nvidia.com/cuda-gpus">支持 CUDA® 的 GPU 卡</a>列表。</li><li>如果 GPU 采用的 CUDA® 架构不受支持，或为了避免从 PTX 进行 JIT 编译，亦或是为了使用不同版本的 NVIDIA® 库，请参阅<a href="https://www.tensorflow.org/install/source">在 Linux 下从源代码编译</a>指南。</li><li>软件包不包含 PTX 代码，但最新支持的 CUDA® 架构除外；因此，如果设置了 <code>CUDA_FORCE_PTX_JIT=1</code>，TensorFlow 将无法在旧款 GPU 上加载。（有关详细信息，请参阅<a href="http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#application-compatibility">应用兼容性</a>。）</li></ul><ol start="2"><li>软件要求</li></ol><p>必须在系统中安装以下 NVIDIA® 软件：</p><ul><li><a href="https://www.nvidia.com/drivers">NVIDIA® GPU 驱动程序</a> - CUDA® 11.2 要求 450.80.02 或更高版本。</li><li><a href="https://developer.nvidia.com/cuda-toolkit-archive">CUDA® 工具包</a>：TensorFlow 支持 CUDA® 11.2（TensorFlow 2.5.0 及更高版本）</li><li>CUDA® 工具包附带的 <a href="http://docs.nvidia.com/cuda/cupti/">CUPTI</a>。</li><li><a href="https://developer.nvidia.com/cudnn">cuDNN SDK 8.1.0</a> <a href="https://developer.nvidia.com/rdp/cudnn-archive">cuDNN 版本</a>。</li><li>（可选）<a href="https://docs.nvidia.com/deeplearning/tensorrt/archives/index.html#trt_6">TensorRT 6.0</a>，可缩短用某些模型进行推断的延迟时间并提高吞吐量。</li></ul><h3 id="下载相应软件"><a href="#下载相应软件" class="headerlink" title="下载相应软件"></a>下载相应软件</h3><ul><li><p>cuda: <a href="https://developer.nvidia.com/cuda-downloads?target_os=Windows&target_arch=x86_64&target_version=10&target_type=exe_local">https://developer.nvidia.com/cuda-downloads?target_os=Windows&amp;target_arch=x86_64&amp;target_version=10&amp;target_type=exe_local</a></p></li><li><p>cuDNN: <a href="https://developer.nvidia.com/rdp/cudnn-archive">https://developer.nvidia.com/rdp/cudnn-archive</a></p></li></ul><p>注：cuDNN下载需要登录Nvidia账号，如果嫌弃官网下载太慢，可以直接从我的百度网盘下载：<br>链接：<a href="https://pan.baidu.com/s/1Aw9mvoeEcOhsJ0qphJ_58Q">https://pan.baidu.com/s/1Aw9mvoeEcOhsJ0qphJ_58Q</a><br>提取码：1234 </p><h3 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h3><blockquote><p>不知道如何配置Path环境变量？参考：<a href="https://www.cnblogs.com/psh1024/p/15555627.html">草履虫都能看懂的系统环境变量配置 - IT-Small-White</a></p></blockquote><ol><li>将下载好的cudnn压缩包进行解压，备用</li><li>安装cuda（安装过程中一定要记下安装路径）</li><li>配置环境变量Path，添加如下内容：</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[你的cuda安装路径]\bin</span><br><span class="line">[你的cuda安装路径]\extras\CUPTI\lib64</span><br><span class="line">[你的cuda安装路径]\include</span><br><span class="line">[你的cudnn解压路径]\bin</span><br></pre></td></tr></table></figure><p>至此，安装启用完毕</p><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><figure class="highlight python"><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">import</span> tensorflow <span class="keyword">as</span> tf</span><br><span class="line"><span class="built_in">print</span>(tf.config.list_physical_devices(<span class="string">&#x27;GPU&#x27;</span>))</span><br></pre></td></tr></table></figure><p>输出结果如下，表明安装成功</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207071314370.png" alt="image-20220707131409327"></p><br><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>使用GPU其实并不一定比CPU更快，这个要看网络结构大小。网络结构比较小的时候，CPU与GPU进行数据传输过程耗时很大，这个时候其实只使用CPU会更快。网络结构比较庞大的时候，GPU的提速效果就比较明显了。</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="配置" scheme="https://blog.pushihao.com/tags/%E9%85%8D%E7%BD%AE/"/>
    
    <category term="tensorflow" scheme="https://blog.pushihao.com/tags/tensorflow/"/>
    
    <category term="机器学习" scheme="https://blog.pushihao.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>如何进行内网穿透</title>
    <link href="https://blog.pushihao.com/article/9f06e0f8.html"/>
    <id>https://blog.pushihao.com/article/9f06e0f8.html</id>
    <published>2022-07-01T01:49:00.000Z</published>
    <updated>2022-07-01T01:49:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是内网穿透"><a href="#什么是内网穿透" class="headerlink" title="什么是内网穿透"></a>什么是内网穿透</h2><p>百度百科：内网穿透，也即 NAT 穿透，进行 NAT 穿透是为了使具有某一个特定源 IP 地址和源端口号的数据包不被 NAT 设备屏蔽而正确路由到内网主机。</p><p>维基百科：在电脑科学中，<strong>NAT穿越</strong>（NAT traversal）涉及 TCP&#x2F;IP 网络中的一个常见问题，即在处于使用了NAT装置的私有 TCP&#x2F;IP 网络中的主机之间建立连接的问题。</p><p>我的理解：内网穿透其实就是把局域网内的资源或服务映射到公网，从而达到通过互联网访问内网的效果。</p><p>根据我的理解，可以做出如下图：</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207011047967.png" alt="image-20220701104714835"> </p><p>因为内网穿透服务器是暴露在互联网（公网）的，所以它必须拥有公网IP地址。用户服务器既可以是公司内部的服务器集群，也可以是PC个人电脑。</p><br><h2 id="一些常见的内网穿透工具的使用"><a href="#一些常见的内网穿透工具的使用" class="headerlink" title="一些常见的内网穿透工具的使用"></a>一些常见的内网穿透工具的使用</h2><h3 id="Ngrok"><a href="#Ngrok" class="headerlink" title="Ngrok"></a>Ngrok</h3><p>官方文档：<a href="https://ngrok.com/docs">https://ngrok.com/docs</a></p><blockquote><p>ngrok是一款非常便捷简单的内网穿透工具。内网穿透服务器由他们来提供，我们只需要指定要穿透的端口即可实现一键内网穿透</p></blockquote><h4 id="下载安装"><a href="#下载安装" class="headerlink" title="下载安装"></a>下载安装</h4><ol><li>从<a href="https://ngrok.com/download">官方下载地址</a>下载对应版本的ngrok</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207011122446.png" alt="image-20220701112204402"></p><ol start="2"><li>下载好后进行解压，会得到如下文件（先别急着运行）</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207011123022.png" alt="image-20220701112307990"> </p><ol start="3"><li>注册一个账号，注册地址：<a href="https://dashboard.ngrok.com/get-started/setup">https://dashboard.ngrok.com/get-started/setup</a></li><li>登录，查看自己的token</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207011128104.png" alt="image-20220701112832070"> </p><ol start="5"><li>在刚刚文件的解压目录下打开cmd窗口</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207011131314.png" alt="image-20220701113119264"> </p><p>至此，安装配置完成</p><h4 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h4><p>在刚刚文件的解压目录下打开cmd窗口，输入<code>ngrok http [要穿透的端口号]</code>回车即可</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202207011137255.png" alt="image-20220701113754212"> </p><p>红框圈住的即为穿透后的地址，通过互联网就可以访问。需要注意的是，免费版的分配的域名地址是随机的，每次穿透可能结果都不一样。</p><br><h3 id="Frp"><a href="#Frp" class="headerlink" title="Frp"></a>Frp</h3><p>官方文档：<a href="https://gofrp.org/docs/">https://gofrp.org/docs/</a></p><blockquote><p>Frp是GitHub上的一个开源项目，使用go语言编写，速度很快，支持点对点内网穿透，功能非常强大</p></blockquote><h4 id="先决条件"><a href="#先决条件" class="headerlink" title="先决条件"></a>先决条件</h4><ul><li>一台具有公网IP的服务器</li><li>知道一丁点Linux相关知识</li></ul><h4 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h4><p>在<a href="https://github.com/fatedier/frp/releases/tag/v0.43.0">Release v0.43.0 · fatedier&#x2F;frp · GitHub</a>下载对应版本的Frp。内网穿透服务器和本机服务器都要由一份。</p><h4 id="使用frp实现http内网穿透"><a href="#使用frp实现http内网穿透" class="headerlink" title="使用frp实现http内网穿透"></a>使用frp实现http内网穿透</h4><div class="note default modern"><p>为了方面描述，内网穿透服务器简称为服务器，要穿透的本机服务器简称为本机</p></div><ol><li>服务器端配置</li></ol><ul><li>打开服务器端 frps.ini 配置文件，修改如下</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="section">[common]</span></span><br><span class="line"><span class="attr">bind_port</span> = <span class="number">7000</span></span><br><span class="line"><span class="attr">vhost_http_port</span> = <span class="number">8080</span></span><br></pre></td></tr></table></figure><ul><li>放行 7000 端口和 8080 端口</li><li>运行命令</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">./frps -c frps.ini</span><br></pre></td></tr></table></figure><ol start="2"><li>本机配置</li></ol><ul><li>打开本机 frpc.ini 配置文件，修改如下</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="section">[common]</span></span><br><span class="line"><span class="attr">server_addr</span> = [服务器ip地址]</span><br><span class="line"><span class="attr">server_port</span> = <span class="number">7000</span></span><br><span class="line"></span><br><span class="line"><span class="section">[web]</span></span><br><span class="line"><span class="attr">type</span> = http</span><br><span class="line"><span class="attr">local_port</span> = [要代理的端口号]</span><br><span class="line"><span class="attr">custom_domains</span> = [域名，没有解析域名的话可以填ip地址]</span><br></pre></td></tr></table></figure><ul><li>运行命令</li></ul><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./frpc.exe <span class="literal">-c</span> ./frpc.ini</span><br></pre></td></tr></table></figure><p>访问 域名.8080 即可看到本机的4000端口对应的资源&#x2F;服务</p><br>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="技术杂谈" scheme="https://blog.pushihao.com/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/"/>
    
    
    <category term="ngrok" scheme="https://blog.pushihao.com/tags/ngrok/"/>
    
    <category term="frp" scheme="https://blog.pushihao.com/tags/frp/"/>
    
    <category term="内网穿透" scheme="https://blog.pushihao.com/tags/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/"/>
    
  </entry>
  
  <entry>
    <title>Hello World!</title>
    <link href="https://blog.pushihao.com/article/1c291ca3.html"/>
    <id>https://blog.pushihao.com/article/1c291ca3.html</id>
    <published>2022-06-30T23:56:00.000Z</published>
    <updated>2025-04-20T07:16:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是-“Hello-World-”"><a href="#什么是-“Hello-World-”" class="headerlink" title="什么是 “Hello, World!”"></a>什么是 “Hello, World!”</h2><p><strong>“Hello, World!” 程序</strong>是编程世界的第一个仪式。</p><p>当你在新语言中写下这行代码并看到它成功输出时，就完成了与这门语言最初的握手。它简单到近乎平淡，却又至关重要——既是初学者验证语法规则的入门练习，也是开发者确认环境配置无误的快速检查。</p><p>这个传统始于1972年贝尔实验室的《A Tutorial Introduction to the Language B》，如今已成为跨越所有编程语言的共同起点。它不只是一段代码，更像是程序员之间的默契：如果连 “Hello, World!” 都跑不通，那更复杂的挑战也不必继续了。</p><h2 id="“Hello-World-”-的-N-种写法"><a href="#“Hello-World-”-的-N-种写法" class="headerlink" title="“Hello, World!” 的 N 种写法"></a>“Hello, World!” 的 N 种写法</h2><h3 id="Ada"><a href="#Ada" class="headerlink" title="Ada"></a>Ada</h3><figure class="highlight ada"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><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">with</span> Ada.Text_IO;</span><br><span class="line"><span class="keyword">use</span> Ada.Text_IO;</span><br><span class="line"><span class="keyword">procedure</span> <span class="title">Hello</span> <span class="keyword">is</span></span><br><span class="line"><span class="keyword">begin</span></span><br><span class="line">    Put_Line (<span class="string">&quot;Hello, World!&quot;</span>);</span><br><span class="line"><span class="keyword">end</span> Hello;</span><br></pre></td></tr></table></figure><h3 id="ALGOL60"><a href="#ALGOL60" class="headerlink" title="ALGOL60"></a>ALGOL60</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">BEGIN DISPLAY(&quot;Hello, World!&quot;) END.</span><br></pre></td></tr></table></figure><h3 id="ALGOL68"><a href="#ALGOL68" class="headerlink" title="ALGOL68"></a>ALGOL68</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">begin</span><br><span class="line">    printf(($gl$,&quot;Hello, World!&quot;))</span><br><span class="line">end</span><br></pre></td></tr></table></figure><h3 id="AppleScript"><a href="#AppleScript" class="headerlink" title="AppleScript"></a>AppleScript</h3><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">say</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">display alert</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Assembly-Language-Linux-x64"><a href="#Assembly-Language-Linux-x64" class="headerlink" title="Assembly Language (Linux x64)"></a>Assembly Language (Linux x64)</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">section .text</span><br><span class="line">global _start</span><br><span class="line"></span><br><span class="line">_start:</span><br><span class="line">    ; sys_write(1, msg, len)</span><br><span class="line">    mov  rax, 1</span><br><span class="line">    mov  rdi, 1</span><br><span class="line">    lea  rsi, [rel msg]</span><br><span class="line">    mov  rdx, len</span><br><span class="line">    syscall</span><br><span class="line"></span><br><span class="line">    ; sys_exit(0)</span><br><span class="line">    mov  rax, 60</span><br><span class="line">    xor  rdi, rdi</span><br><span class="line">    syscall</span><br><span class="line"></span><br><span class="line">section .rodata</span><br><span class="line">msg: db &quot;Hello, World!&quot;, 0xA</span><br><span class="line">len: equ $ - msg</span><br></pre></td></tr></table></figure><h3 id="BASIC"><a href="#BASIC" class="headerlink" title="BASIC"></a>BASIC</h3><figure class="highlight basic"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">PRINT</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Batchfile"><a href="#Batchfile" class="headerlink" title="Batchfile"></a>Batchfile</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@echo off</span><br><span class="line">echo Hello, World!</span><br></pre></td></tr></table></figure><h3 id="Bash"><a href="#Bash" class="headerlink" title="Bash"></a>Bash</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="C"><a href="#C" class="headerlink" title="C"></a>C</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Hello, World!&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="C-1"><a href="#C-1" class="headerlink" title="C++"></a>C++</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Hello, World!&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="c"><a href="#c" class="headerlink" title="c#"></a>c#</h3><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Console.WriteLine(<span class="string">&quot;Hello, World!&quot;</span>);</span><br></pre></td></tr></table></figure><h3 id="Clojure"><a href="#Clojure" class="headerlink" title="Clojure"></a>Clojure</h3><figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(<span class="name">println</span> <span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="COBOL"><a href="#COBOL" class="headerlink" title="COBOL"></a>COBOL</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">IDENTIFICATION DIVISION.</span><br><span class="line">PROGRAM-ID. HELLO-WORLD.</span><br><span class="line">* simple hello world program</span><br><span class="line">PROCEDURE DIVISION.</span><br><span class="line">    DISPLAY &#x27;Hello, World!&#x27;.</span><br><span class="line">    STOP RUN.</span><br></pre></td></tr></table></figure><h3 id="D"><a href="#D" class="headerlink" title="D"></a>D</h3><figure class="highlight d"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">import</span> std.stdio;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> main() &#123;</span><br><span class="line">    writeln(<span class="string">&quot;Hello, World!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Dart"><a href="#Dart" class="headerlink" title="Dart"></a>Dart</h3><figure class="highlight dart"><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">void</span> main() &#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;Hello, World!&#x27;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Elixir"><a href="#Elixir" class="headerlink" title="Elixir"></a>Elixir</h3><figure class="highlight elixir"><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_">IO</span>.puts(<span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Ezhil"><a href="#Ezhil" class="headerlink" title="Ezhil"></a>Ezhil</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">பதிப்பி &quot;உலகே வணக்கம்&quot;</span><br><span class="line">பதிப்பி &quot;Hello, World!&quot;</span><br><span class="line">exit()</span><br></pre></td></tr></table></figure><h3 id="Forth"><a href="#Forth" class="headerlink" title="Forth"></a>Forth</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.&quot; Hello, World!&quot; CR</span><br></pre></td></tr></table></figure><h3 id="Fortran"><a href="#Fortran" class="headerlink" title="Fortran"></a>Fortran</h3><figure class="highlight fortran"><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="function"><span class="keyword">program</span></span> Hello</span><br><span class="line">    <span class="built_in">print</span> *, <span class="string">&quot;Hello, World!&quot;</span></span><br><span class="line"><span class="keyword">end</span> <span class="function"><span class="keyword">program</span></span> Hello</span><br></pre></td></tr></table></figure><h3 id="Go"><a href="#Go" class="headerlink" title="Go"></a>Go</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><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">package</span> main</span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    fmt.Println(<span class="string">&quot;Hello, World!&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Haskell"><a href="#Haskell" class="headerlink" title="Haskell"></a>Haskell</h3><figure class="highlight haskell"><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="title">main</span> :: <span class="type">IO</span> ()</span><br><span class="line"><span class="title">main</span> = putStrLn <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Java"><a href="#Java" class="headerlink" title="Java"></a>Java</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</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">        System.out.println(<span class="string">&quot;Hello, World!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="JavaScript"><a href="#JavaScript" class="headerlink" title="JavaScript"></a>JavaScript</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Hello, World!&quot;</span>);</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">write</span>(<span class="string">&quot;Hello, World!&quot;</span>);</span><br></pre></td></tr></table></figure><h3 id="Julia"><a href="#Julia" class="headerlink" title="Julia"></a>Julia</h3><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">println(<span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Kotlin"><a href="#Kotlin" class="headerlink" title="Kotlin"></a>Kotlin</h3><figure class="highlight kotlin"><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="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    println(<span class="string">&quot;Hello, World!&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Lisp"><a href="#Lisp" class="headerlink" title="Lisp"></a>Lisp</h3><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(<span class="name">print</span> <span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Logo"><a href="#Logo" class="headerlink" title="Logo"></a>Logo</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">print [Hello, World!]</span><br></pre></td></tr></table></figure><h3 id="Lua"><a href="#Lua" class="headerlink" title="Lua"></a>Lua</h3><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Objective-C"><a href="#Objective-C" class="headerlink" title="Objective-C"></a>Objective-C</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#import &lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;Hello, World!\n&quot;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">#import &lt;Foundation/Foundation.h&gt;</span><br><span class="line"></span><br><span class="line">int main(int argc, const char * argv[]) &#123;</span><br><span class="line">    @autoreleasepool &#123;</span><br><span class="line">        NSLog(@&quot;Hello, World!&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="OCaml"><a href="#OCaml" class="headerlink" title="OCaml"></a>OCaml</h3><figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">print_endline <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Pascal"><a href="#Pascal" class="headerlink" title="Pascal"></a>Pascal</h3><figure class="highlight pascal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">program</span> Hello;</span><br><span class="line"><span class="keyword">begin</span></span><br><span class="line">    writeln (<span class="string">&#x27;Hello, World!&#x27;</span>);</span><br><span class="line"><span class="keyword">end</span>.</span><br></pre></td></tr></table></figure><h3 id="Perl"><a href="#Perl" class="headerlink" title="Perl"></a>Perl</h3><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">print</span> <span class="string">&quot;Hello, World!\n&quot;</span>;</span><br></pre></td></tr></table></figure><h3 id="Perl6"><a href="#Perl6" class="headerlink" title="Perl6"></a>Perl6</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">say &#x27;Hello, World!&#x27;</span><br></pre></td></tr></table></figure><h3 id="PHP"><a href="#PHP" class="headerlink" title="PHP"></a>PHP</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line">    <span class="keyword">echo</span> <span class="string">&#x27;Hello, World!&#x27;</span>;</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure><h3 id="PowerShell"><a href="#PowerShell" class="headerlink" title="PowerShell"></a>PowerShell</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;Hello, World!&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="Prolog"><a href="#Prolog" class="headerlink" title="Prolog"></a>Prolog</h3><figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">main() :- write(<span class="string">&quot;Hello, World!&quot;</span>), nl.</span><br></pre></td></tr></table></figure><h3 id="Python2"><a href="#Python2" class="headerlink" title="Python2"></a>Python2</h3><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="built_in">print</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Python3"><a href="#Python3" class="headerlink" title="Python3"></a>Python3</h3><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="built_in">print</span>(<span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="R"><a href="#R" class="headerlink" title="R"></a>R</h3><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">print<span class="punctuation">(</span><span class="string">&quot;Hello, World!&quot;</span><span class="punctuation">)</span></span><br></pre></td></tr></table></figure><h3 id="Racket"><a href="#Racket" class="headerlink" title="Racket"></a>Racket</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#lang cli</span><br><span class="line">(displayln &quot;Hello, World!&quot;)</span><br></pre></td></tr></table></figure><h3 id="Ruby"><a href="#Ruby" class="headerlink" title="Ruby"></a>Ruby</h3><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">puts <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Rust"><a href="#Rust" class="headerlink" title="Rust"></a>Rust</h3><figure class="highlight rust"><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">fn</span> <span class="title function_">main</span>() &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Hello, World!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Simula"><a href="#Simula" class="headerlink" title="Simula"></a>Simula</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Begin</span><br><span class="line">    OutText (&quot;Hello, World!&quot;);</span><br><span class="line">    Outimage;</span><br><span class="line">End;</span><br></pre></td></tr></table></figure><h3 id="Smalltalk"><a href="#Smalltalk" class="headerlink" title="Smalltalk"></a>Smalltalk</h3><figure class="highlight smalltalk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Transcript</span> show: <span class="string">&#x27;Hello, World!&#x27;</span>.</span><br></pre></td></tr></table></figure><h3 id="Standard-ML"><a href="#Standard-ML" class="headerlink" title="Standard ML"></a>Standard ML</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">print &quot;Hello, World!\n&quot;</span><br></pre></td></tr></table></figure><h3 id="Swift"><a href="#Swift" class="headerlink" title="Swift"></a>Swift</h3><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Tcl"><a href="#Tcl" class="headerlink" title="Tcl"></a>Tcl</h3><figure class="highlight tcl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">puts</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="TI-BASIC"><a href="#TI-BASIC" class="headerlink" title="TI-BASIC"></a>TI-BASIC</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:Disp &quot;Hello, World!&quot;</span><br></pre></td></tr></table></figure><h3 id="VBScript"><a href="#VBScript" class="headerlink" title="VBScript"></a>VBScript</h3><figure class="highlight vbscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WScript.Echo <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><h3 id="WebAssembly-Text-Format"><a href="#WebAssembly-Text-Format" class="headerlink" title="WebAssembly Text Format"></a>WebAssembly Text Format</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">(module</span><br><span class="line">    (import &quot;console&quot; &quot;log&quot; (func $log (param i32)))</span><br><span class="line">    (memory 1)</span><br><span class="line">    (data (i32.const 0) &quot;Hello, World!\00&quot;)</span><br><span class="line">    (func (export &quot;hello&quot;)</span><br><span class="line">        (call $log (i32.const 0))</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h3 id="易语言"><a href="#易语言" class="headerlink" title="易语言"></a>易语言</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">信息框（“Hello, World!”,0,,）</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">第一行代码从 &#39;Hello, world!&#39; 开始！</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Git基本使用</title>
    <link href="https://blog.pushihao.com/article/2df4f2b8.html"/>
    <id>https://blog.pushihao.com/article/2df4f2b8.html</id>
    <published>2022-06-27T12:59:00.000Z</published>
    <updated>2024-10-16T12:38:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>曾经稍微学习过一点git，对git稍微有一点认识，但也仅仅是知道他是干嘛的。本<strong>笔记</strong>主要用来记录一下git的<strong>常用</strong>命令和功能以及我的一些个人理解。</p><br><h2 id="什么是git"><a href="#什么是git" class="headerlink" title="什么是git"></a>什么是git</h2><p>对于什么是git，官方文档是这样介绍它的：<br>Git is a fast, scalable, distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals.</p><p>总结下来，git是一个<mark class="hl-label green">可扩展的</mark>、<mark class="hl-label green">分布式的</mark><mark class="hl-label green">版本控制系统</mark>。</p><br><h2 id="安装git"><a href="#安装git" class="headerlink" title="安装git"></a>安装git</h2><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">windows</button><button type="button" class="tab">Linux</button></div><div class="tab-contents"><div class="tab-item-content active"><p>通过<a href="https://git-scm.com/download/win">官方下载网站</a>下载相应安装包正常安装，当鼠标右键出现<code>Git Bash Here</code>时即为安装成功</p></div><div class="tab-item-content"><p>对于Debian&#x2F;Ubuntu等一些常见的Linux发行版，可以直接通过默认的包管理工具进行安装，参照<a href="https://git-scm.com/download/linux">官方Linux安装指南</a></p><br><p>也可以通过源码进行安装，源码安装方式如下：</p><p>在该<a href="https://mirrors.edge.kernel.org/pub/software/scm/git/">镜像网站</a>下载对应版本的git源码，然后<code>./configure prefix=/usr/local/git/</code>，然后<code>make &amp;&amp; make install</code>，最后将git指令添加到环境变量即可</p></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><p>安装完git之后，必须配置用户名和邮件，配置方式如下（二选一即可）：</p><ul><li>使用命令行</li></ul><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config <span class="literal">--global</span> user.name <span class="string">&quot;Your Name&quot;</span></span><br><span class="line">git config <span class="literal">--global</span> user.email <span class="string">&quot;Your Email&quot;</span></span><br></pre></td></tr></table></figure><ul><li>编辑 ~&#x2F;.gitconfig 或者 &#x2F;etc&#x2F;gitconfig 文件</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[user]</span><br><span class="line">name = Your Name</span><br><span class="line">email = Your Email</span><br></pre></td></tr></table></figure><br><h2 id="创建git仓库"><a href="#创建git仓库" class="headerlink" title="创建git仓库"></a>创建git仓库</h2><p>进入到要创建仓库的目录下</p><ul><li>输入<code>git init</code>即可创建一个空仓库</li><li>输入<code>git add [文件名]</code>即可把文件写入暂存区（文件名支持通配符，如*.cpp）</li><li>输入<code>git commit -m [提交原因]</code>即可把<mark class="hl-label green">暂存区</mark>修改写入当前分支</li></ul><p>注：可以add多次后进行commit，一次commit即可把暂存区全部修改提交到当前分支版本库</p><br><h2 id="版本控制"><a href="#版本控制" class="headerlink" title="版本控制"></a>版本控制</h2><h3 id="状态查看"><a href="#状态查看" class="headerlink" title="状态查看"></a>状态查看</h3><p><code>git status</code>命令可以查看工作区的状态，也可以查看哪些文件被修改了</p><p><code>git diff</code>命令可以查看文件修改的具体内容，但是无法查看二进制文件如word文档，图片等的修改内容</p><h3 id="版本回退"><a href="#版本回退" class="headerlink" title="版本回退"></a>版本回退</h3><p><code>git log</code>命令可以查看<strong>提交历史</strong>commit id（版本号）、作者、邮箱、日期以及commit的原因，如果只想查看版本号以及commit原因，可以加上一个参数，使用如下命令<code>git log --pretty=online</code>，常用于<mark class="hl-label green">撤销</mark>操作</p><p><code>git reflog</code>命令可以查看<strong>命令历史</strong>的commit id等相关信息，常用于撤销后的<mark class="hl-label green">重做</mark>操作</p><p><code>git reset --hard commit-id</code>命令可以使文件在不同版本之间跳转，需要注意的是，在git中 HEAD 表示当前版本，那么 HEAD^ 就表示上一个版本，HEAD^^ 就表示上上一个版本，如<code>git reset --hard HEAD^</code>就表示回到上一个版本</p><h3 id="撤销修改"><a href="#撤销修改" class="headerlink" title="撤销修改"></a>撤销修改</h3><p><code>git checkout -- [文件名]</code>命令可以丢弃工作区的修改，使用此命令会产生两种情况</p><ul><li>该文件自修改后还未放到暂存区，那么执行此命令后该文件就回到了当前版本库（最后一次commit）的状态</li><li>该文件已经添加到了暂存区，那么执行此命令后文件就回到了暂存区（最后一次add）的状态</li></ul><div class="note blue no-icon flat"><p>小提示：此命令也可用于在工作区误删文件后的文件恢复</p></div><p><code>git restore --worktree [文件名]</code>命令可以将文件回到暂存区状态</p><p><code>git reset HEAD [文件名]</code>命令清除所有暂存区的内容，对工作区没有影响</p><h3 id="删除文件"><a href="#删除文件" class="headerlink" title="删除文件"></a>删除文件</h3><p><code>git rm [文件名]</code>命令可以将文件从<strong>版本库</strong>中删除</p><br><h2 id="分支管理"><a href="#分支管理" class="headerlink" title="分支管理"></a>分支管理</h2><blockquote><p>一个分支下的修改不会影响到其他分支，所以往往使用一个dev分支做具体项目开发，该分支下又有多个子分支来实现不同的功能和细节，每当有一个具体的新版本发布，就将dev分支合并到master分支。master分支往往不会进行具体的操作，只是负责发布稳定版本</p></blockquote><p><code>git branch</code>命令可以查看当前分支</p><p><code>git checkout -b [分支名]</code>创建并切换到新分支 &#x3D; <code>git branch [分支名]</code>创建新分支 + <code>git checkout [分支名]</code>切换到一个已有分支</p><div class="note warning no-icon flat"><p>注意：此命令与上述撤销修改命令有些相似，可以会难以区分，推荐使用下述命令</p></div><p><code>git switch -c [分支名]</code>创建并切换到新分支</p><p><code>git switch [分支名]</code>切换到一个已有分支</p><p><code>git merge [分支名]</code>把指定分支名的修改合并到当前分支，默认以Fast-forword模式合并</p><p><code>git branch -d [分支名]</code>删除分支</p><p><code>git merge --no-ff -m [提交原因] [分支名]</code>以普通模式将dev合并到当前分支，并进行一次提交</p><br><h2 id="标签管理"><a href="#标签管理" class="headerlink" title="标签管理"></a>标签管理</h2><blockquote><p>标签其实就是给某次commit打上一个记号，常用于版本发布时的版本号。有点类似于给commit id起个名字</p></blockquote><p><code>git tag</code>查看所有标签</p><p><code>git tag [标签名] ([commit id])</code>给指定commit打上一个标签，默认是HEAD</p><p><code>git tag -a [标签名] -m [描述信息] ([commit id])</code>打上一个标签，并添加描述信息</p><p><code>git show [标签名]</code>查看标签信息</p><p><code>git tag -d [标签名]</code>可以删除一个标签</p><br><h2 id="远程仓库"><a href="#远程仓库" class="headerlink" title="远程仓库"></a>远程仓库</h2><blockquote><p>远程仓库就是一个搭建在服务器上的git仓库。通过git工具，我们可以很方便的将远程仓库的内容拉取到本地，也可以将本地的内容推送到远程仓库</p></blockquote><p><code>ssh-keygen -t rsa -C [邮箱地址]</code>输入命令后一直回车即可。此命令可以生成一个rsa公钥，默认存放在 C:&#x2F;user&#x2F;用户名&#x2F;.ssh 目录下，id_rsa是密钥，id_rsa.pub是公钥。将公钥放到远程仓库的 SSH Keys 中即可实现对远程私有仓库的读写，类似于一个身份证</p><p><code>git clone [仓库地址]</code>将远程仓库克隆到本地，仓库地址有以git开头的ssh协议和以http&#x2F;https开头的http&#x2F;https协议以及一些其他的如github-cli协议</p><p><code>git remote add [仓库名称] [仓库地址]</code>添加远程仓库，仓库名称通常命名为origin，这是默认的叫法</p><p><code>git push -u origin main</code>把本地的master分支推送到远程的origin仓库，只需要在第一次加上 -u 参数</p><p><code>git push origin [标签名]</code>将一个本地标签推送到远程服务器</p><p><code>git push origin --tags</code>将所有标签推送到远程服务器</p><p><code>git push origin :refs/tags/[标签名]</code>删除一个远程标签</p><p><code>git fetch [仓库地址] ([分支名])</code>将远程仓库的指定分支取回到本地，不填分支名则默认是所有分支</p><p><code>git pull</code>从远程仓库获取最新版本并合并到本地 &#x3D; <code>git fetch</code> + <code>git merge</code></p><p>实战：拉取远程仓库的dev分支并关联到本地dev分支</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"><span class="meta prompt_"># </span><span class="language-bash">新建本地仓库</span></span><br><span class="line">git init</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加远程仓库</span></span><br><span class="line">git remote add origin https://github.com/itgrape/study.git</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">拉取远程指定分支</span></span><br><span class="line">git fetch origin dev</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">新建本地dev分支并关联到远程dev分支</span></span><br><span class="line">git switch -c dev origin/dev</span><br></pre></td></tr></table></figure><br><h2 id="git子模块的使用"><a href="#git子模块的使用" class="headerlink" title="git子模块的使用"></a>git子模块的使用</h2><blockquote><p>有种情况我们经常会遇到：某个工作中的项目需要包含并使用另一个项目。 也许是第三方库，或者你独立开发的，用于多个父项目的库。 现在问题来了：你想要把它们当做两个独立的项目，同时又想在一个项目中使用另一个</p><p>git 子模块就是在一个 git 仓库中嵌套另一个&#x2F;多个 git 仓库，有点像套娃。我们可以对每一个子模块单独进行管理</p></blockquote><h3 id="添加子模块"><a href="#添加子模块" class="headerlink" title="添加子模块"></a>添加子模块</h3><p><code>git submodule add [仓库地址] [存放路径]</code> 在父项目中添加一个子模块</p><p><code>git submodule</code> 查看所有子模块</p><p><code>git submodule update --remote [子模块名]</code> 更新指定子模块</p><p><code>git submodule update --remote</code> 更新所有子模块</p><p><code>git push origin HEAD:master</code> 子模块向远程仓库提交修改</p><h3 id="克隆一个含有子模块的项目"><a href="#克隆一个含有子模块的项目" class="headerlink" title="克隆一个含有子模块的项目"></a>克隆一个含有子模块的项目</h3><p>方法一：先克隆父项目，然后克隆子项目</p><ol><li><p><code>git clone [父项目地址]</code> 克隆父项目</p></li><li><p><code>git submodule init</code> 初始化本地子模块配置文件</p></li><li><p><code>git submodule update</code> 从该项目中抓取所有数据并检出父项目中列出的合适的提交</p></li></ol><p>方法一简化：命令合二为一</p><ul><li><p><code>git submodule update --init</code> &#x3D; <code>git submodule init</code> + <code>git submodule update</code></p></li><li><p>如果还要初始化、抓取并检出任何嵌套的子模块，可以使用 <code>git submodule update --init --recursive</code></p></li></ul><p>方法二：递归克隆父项目和子项目</p><p><code>git clone --recurse-submodules [父项目地址]</code> 自动初始化并更新仓库中的每一个子模块， 包括可能存在的嵌套子模块</p><h3 id="删除子模块"><a href="#删除子模块" class="headerlink" title="删除子模块"></a>删除子模块</h3><ol><li>删除子模块文件夹</li></ol><p><code>rm -rf [子模块名]</code></p><ol start="2"><li>删除 .gitmodules 文件中的子模块信息</li><li>删除 .git&#x2F;config 文件中的子模块信息</li><li>删除 .git&#x2F;module&#x2F; 目录下的子模块的目录</li></ol><p><code>rm .git/module/[子模块名]</code></p><ol start="5"><li>清除子模块缓存</li></ol><p><code>git rm --cached [子模块名]</code></p><br><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p>【1】：<a href="https://git-scm.com/docs">Git-Reference</a></p><p>【2】：<a href="https://www.liaoxuefeng.com/wiki/896043488029600/896067008724000">廖雪峰的官方网站</a></p><p>【3】：<a href="https://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html">阮一峰的网络日志</a></p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="团队协作" scheme="https://blog.pushihao.com/tags/%E5%9B%A2%E9%98%9F%E5%8D%8F%E4%BD%9C/"/>
    
    <category term="Git" scheme="https://blog.pushihao.com/tags/Git/"/>
    
  </entry>
  
  <entry>
    <title>Butterfly常用标签外挂</title>
    <link href="https://blog.pushihao.com/article/a2b56279.html"/>
    <id>https://blog.pushihao.com/article/a2b56279.html</id>
    <published>2022-06-24T14:51:20.000Z</published>
    <updated>2025-05-29T01:03:54.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>我也是最近刚了解到Hexo的标签外挂，同时也觉得他很方便。于是想写一篇笔记记录一下它的基本语法，看了一些网上的教程，结果<code>hexo g</code>的时候控制台一阵爆红。果然，看教程还是看官方文档比较靠谱。</p><p>本文参考：<a href="https://butterfly.js.org/posts/4aa8abbe/#%E6%A8%99%E7%B1%A4%E5%A4%96%E6%8E%9B%EF%BC%88Tag-Plugins%EF%BC%89">標籤外掛（Tag Plugins）</a></p><br><h2 id="什么是标签外挂？"><a href="#什么是标签外挂？" class="headerlink" title="什么是标签外挂？"></a>什么是标签外挂？</h2><p>标签外挂也叫外挂标签，我的理解就是Hexo对于markdown的<strong>扩展语法</strong>（其实就是通过CSS代码修改文章特定语法的文字的样式），它是Hexo博客框架所独有的。通过使用标签外挂，可以让markdown语法具备更强的表达能力。一般不同的主题或者CSS样式提供的标签外挂语法也是不一样的。我这里介绍的主要是Butterfly主题所提供的标签外挂语法。</p><br><h2 id="常用标签外挂语法"><a href="#常用标签外挂语法" class="headerlink" title="常用标签外挂语法"></a>常用标签外挂语法</h2><h3 id="分区标签tabs"><a href="#分区标签tabs" class="headerlink" title="分区标签tabs"></a>分区标签tabs</h3><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">&#123;% tabs Tags %&#125;</span><br><span class="line">&lt;!-- tab 标题1 --&gt;</span><br><span class="line">内容1</span><br><span class="line">&lt;!-- endtab --&gt;</span><br><span class="line">&lt;!-- tab 标题2 --&gt;</span><br><span class="line">内容2</span><br><span class="line">&#123;% tabs Tags %&#125;</span><br><span class="line">&lt;!-- tab 标题2.1 --&gt;</span><br><span class="line">内容2.1</span><br><span class="line">&lt;!-- endtab --&gt;</span><br><span class="line">&lt;!-- tab 标题2.2 --&gt;</span><br><span class="line">内容2.2</span><br><span class="line">&lt;!-- endtab --&gt;</span><br><span class="line">&#123;% endtabs %&#125;</span><br><span class="line">&lt;!-- endtab --&gt;</span><br><span class="line">&#123;% endtabs %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">标题1</button><button type="button" class="tab">标题2</button></div><div class="tab-contents"><div class="tab-item-content active"><p>内容1</p></div><div class="tab-item-content"><p>内容2</p><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">标题2.1</button><button type="button" class="tab">标题2.2</button></div><div class="tab-contents"><div class="tab-item-content active"><p>内容2.1</p></div><div class="tab-item-content"><p>内容2.2</p></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="时间轴标签timeline"><a href="#时间轴标签timeline" class="headerlink" title="时间轴标签timeline"></a>时间轴标签timeline</h3><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><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">&#123;% timeline 2020, green %&#125;</span><br><span class="line"></span><br><span class="line">&lt;!-- timeline 09 --&gt;</span><br><span class="line">计算机小萌新</span><br><span class="line">&lt;!-- endtimeline --&gt;</span><br><span class="line"></span><br><span class="line">&#123;% endtimeline %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% timeline 2021, green %&#125;</span><br><span class="line"></span><br><span class="line">&lt;!-- timeline 03 --&gt;</span><br><span class="line">尝试上云</span><br><span class="line">&lt;!-- endtimeline --&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- timeline 09 --&gt;</span><br><span class="line">第一次搭建个人博客</span><br><span class="line">&lt;!-- endtimeline --&gt;</span><br><span class="line"></span><br><span class="line">&#123;% endtimeline %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="timeline  green"><div class='timeline-item headline'>        <div class='timeline-item-title'>          <div class='item-circle'><p>2020</p></div>        </div>      </div><div class='timeline-item'>        <div class='timeline-item-title'>          <div class='item-circle'><p>09</p></div>        </div>        <div class='timeline-item-content'><p>计算机小萌新</p></div>      </div></div><div class="timeline  green"><div class='timeline-item headline'>        <div class='timeline-item-title'>          <div class='item-circle'><p>2021</p></div>        </div>      </div><div class='timeline-item'>        <div class='timeline-item-title'>          <div class='item-circle'><p>03</p></div>        </div>        <div class='timeline-item-content'><p>尝试上云</p></div>      </div><div class='timeline-item'>        <div class='timeline-item-title'>          <div class='item-circle'><p>09</p></div>        </div>        <div class='timeline-item-content'><p>第一次搭建个人博客</p></div>      </div></div><h3 id="相册图库gallery"><a href="#相册图库gallery" class="headerlink" title="相册图库gallery"></a>相册图库gallery</h3><p>代码展示：</p><figure class="highlight markdown"><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="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;gallery-group-main&quot;</span>&gt;</span></span></span><br><span class="line">&#123;% galleryGroup &#x27;壁纸&#x27; &#x27;收藏的一些壁纸&#x27; &#x27;/gallery/wallpaper&#x27; https://img.pushihao.com/typora/202505281847210.png %&#125;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="gallery-group-main"><figure class="gallery-group">    <img class="gallery-group-img no-lightbox" src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202505281847210.png" alt="Group Image Gallery">    <figcaption>      <div class="gallery-group-name">壁纸</div>      <p>收藏的一些壁纸</p>      <a href='/gallery/wallpaper'></a>    </figcaption>  </figure></div><h3 id="相册gallery"><a href="#相册gallery" class="headerlink" title="相册gallery"></a>相册gallery</h3><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><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">&#123;% gallery %&#125;</span><br><span class="line">![<span class="string">Fze9jchtnyJXMHN.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505281852188.jpg</span>)</span><br><span class="line">![<span class="string">ryLVePaqkYm4TEK.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290840741.jpg</span>)</span><br><span class="line">![<span class="string">gEy5Zc1Ai6VuO4N.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290840937.jpg</span>)</span><br><span class="line">![<span class="string">d6QHbytlSYO4FBG.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290840435.jpg</span>)</span><br><span class="line">![<span class="string">6nepIJ1xTgufatZ.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839102.jpg</span>)</span><br><span class="line">![<span class="string">E7Jvr4eIPwUNmzq.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839657.jpg</span>)</span><br><span class="line">![<span class="string">mh19anwBSWIkGlH.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839323.jpg</span>)</span><br><span class="line">![<span class="string">2tu9JC8ewpBFagv.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839254.jpg</span>)</span><br><span class="line">&#123;% endgallery %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="gallery-container" data-type="data" data-button="" data-limit="10" data-first="10">    <div class="gallery-items">[{"url":"https://img.pushihao.com/typora/202505281852188.jpg","alt":"Fze9jchtnyJXMHN.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290840741.jpg","alt":"ryLVePaqkYm4TEK.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290840937.jpg","alt":"gEy5Zc1Ai6VuO4N.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290840435.jpg","alt":"d6QHbytlSYO4FBG.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839102.jpg","alt":"6nepIJ1xTgufatZ.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839657.jpg","alt":"E7Jvr4eIPwUNmzq.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839323.jpg","alt":"mh19anwBSWIkGlH.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839254.jpg","alt":"2tu9JC8ewpBFagv.jpg","title":""}]</div>  </div><h3 id="标签隐藏标签"><a href="#标签隐藏标签" class="headerlink" title="标签隐藏标签"></a>标签隐藏标签</h3><h4 id="行内隐藏hideInline"><a href="#行内隐藏hideInline" class="headerlink" title="行内隐藏hideInline"></a>行内隐藏hideInline</h4><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">门里站着一个人? &#123;% hideInline 闪, 查看答案, orange, white %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><p>上辈子如果你是一种饮料，那一定是碳酸饮料 <span class="hide-inline"><button type="button" class="hide-button" style="background-color:  green;color:  white"> 为什么?</button><span class="hide-content">因为我一看见你就开心得冒泡呀</span></span></p><p>门里站着一个人? <span class="hide-inline"><button type="button" class="hide-button" style="background-color:  orange;color:  white"> 查看答案</button><span class="hide-content">闪</span></span></p><h4 id="块隐藏hideBlock"><a href="#块隐藏hideBlock" class="headerlink" title="块隐藏hideBlock"></a>块隐藏hideBlock</h4><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><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">&#123;% hideBlock 查看隐藏内容, green, white %&#125;</span><br><span class="line">&#123;% gallery %&#125;</span><br><span class="line">![<span class="string">Fze9jchtnyJXMHN.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505281852188.jpg</span>)</span><br><span class="line">![<span class="string">ryLVePaqkYm4TEK.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290840741.jpg</span>)</span><br><span class="line">![<span class="string">gEy5Zc1Ai6VuO4N.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290840937.jpg</span>)</span><br><span class="line">![<span class="string">d6QHbytlSYO4FBG.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290840435.jpg</span>)</span><br><span class="line">![<span class="string">6nepIJ1xTgufatZ.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839102.jpg</span>)</span><br><span class="line">![<span class="string">E7Jvr4eIPwUNmzq.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839657.jpg</span>)</span><br><span class="line">![<span class="string">mh19anwBSWIkGlH.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839323.jpg</span>)</span><br><span class="line">![<span class="string">2tu9JC8ewpBFagv.jpg</span>](<span class="link">https://img.pushihao.com/typora/202505290839254.jpg</span>)</span><br><span class="line">&#123;% endgallery %&#125;</span><br><span class="line">&#123;% endhideBlock %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="hide-block"><button type="button" class="hide-button" style="background-color:  green;color:  white">查看隐藏内容</button><div class="hide-content"><div class="gallery-container" data-type="data" data-button="" data-limit="10" data-first="10">    <div class="gallery-items">[{"url":"https://img.pushihao.com/typora/202505281852188.jpg","alt":"Fze9jchtnyJXMHN.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290840741.jpg","alt":"ryLVePaqkYm4TEK.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290840937.jpg","alt":"gEy5Zc1Ai6VuO4N.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290840435.jpg","alt":"d6QHbytlSYO4FBG.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839102.jpg","alt":"6nepIJ1xTgufatZ.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839657.jpg","alt":"E7Jvr4eIPwUNmzq.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839323.jpg","alt":"mh19anwBSWIkGlH.jpg","title":""},{"url":"https://img.pushihao.com/typora/202505290839254.jpg","alt":"2tu9JC8ewpBFagv.jpg","title":""}]</div>  </div></div></div><h4 id="折叠框hideToggle"><a href="#折叠框hideToggle" class="headerlink" title="折叠框hideToggle"></a>折叠框hideToggle</h4><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><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">&#123;% hideToggle 我的博客信息 %&#125;</span><br><span class="line"><span class="bullet">-</span> 博客名称: 葡萄</span><br><span class="line"><span class="bullet">-</span> 博客链接: https://blog.pushihao.com</span><br><span class="line"><span class="bullet">-</span> 博客头像: https://blog.pushihao.com/img/avatar.webp</span><br><span class="line"><span class="bullet">-</span> 博客描述: 没事写两句</span><br><span class="line">&#123;% endhideToggle %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><details class="toggle" ><summary class="toggle-button" style="">我的博客信息</summary><div class="toggle-content"><ul><li><p>博客名称: 葡萄</p></li><li><p>博客链接: <a href="https://blog.pushihao.com/">https://blog.pushihao.com</a></p></li><li><p>博客头像: <a href="https://blog.pushihao.com/img/avatar.webp">https://blog.pushihao.com/img/avatar.webp</a></p></li><li><p>博客描述: 没事写两句</p></li></ul></div></details><h3 id="按钮标签btn"><a href="#按钮标签btn" class="headerlink" title="按钮标签btn"></a>按钮标签btn</h3><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">&#123;% btn [url],[text],[icon],[color] [style] [layout] [position] [size] %&#125;</span><br><span class="line"></span><br><span class="line">[url]         : 链接</span><br><span class="line">[text]        : 按钮文字</span><br><span class="line">[icon]        : [可选] 圖標</span><br><span class="line">[color]       : [可选] 按钮背景颜色(默认style时）</span><br><span class="line">                      按钮字体和边框颜色(outline时)</span><br><span class="line">                      default/blue/pink/red/purple/orange/green</span><br><span class="line">[style]       : [可选] 按钮样式 默认实心</span><br><span class="line">                      outline/留空</span><br><span class="line">[layout]      : [可选] 按钮布局 默认为line</span><br><span class="line">                      block/留空</span><br><span class="line">[position]    : [可选] 按钮位置 前提是设置了layout为block 默认为左边</span><br><span class="line">                      center/right/留空</span><br><span class="line">[size]        : [可选] 按钮大小</span><br><span class="line">                      larger/留空</span><br></pre></td></tr></table></figure><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这是我的博客 &#123;% btn https://blog.pushihao.com, 葡萄, far fa-hand-point-right, green %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><p>这是我的博客 <a class="btn-beautify green" href="https://blog.pushihao.com" title="葡萄"><i class="far fa-hand-point-right"></i><span>葡萄</span></a></p><h3 id="高亮文字标签label"><a href="#高亮文字标签label" class="headerlink" title="高亮文字标签label"></a>高亮文字标签label</h3><p>代码展示：</p><figure class="highlight markdown"><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">对 &#123;% label 潇潇暮雨洒江天 %&#125;，一番&#123;% label 洗清秋 blue %&#125;。渐霜风凄紧，&#123;% label 关河冷落 pink %&#125;，&#123;% label 残照当楼 red %&#125;。是处红衰翠减，苒苒物华休。惟有长江水，无语东流。</span><br><span class="line"></span><br><span class="line">&#123;% label 不忍登高临远 purple %&#125;，望故乡渺邈，归思难收。叹年来踪迹，&#123;% label 何事苦淹留 orange %&#125;？想佳人、&#123;% label 妆楼颙望 green %&#125;，误几回、天际识归舟。争知我，倚栏杆处，正恁凝愁！</span><br></pre></td></tr></table></figure><p>效果展示：</p><p>对 <mark class="hl-label default">潇潇暮雨洒江天</mark>，一番<mark class="hl-label blue">洗清秋</mark>。渐霜风凄紧，<mark class="hl-label pink">关河冷落</mark>，<mark class="hl-label red">残照当楼</mark>。是处红衰翠减，苒苒物华休。惟有长江水，无语东流。</p><mark class="hl-label purple">不忍登高临远</mark>，望故乡渺邈，归思难收。叹年来踪迹，<mark class="hl-label orange">何事苦淹留</mark>？想佳人、<mark class="hl-label green">妆楼颙望</mark>，误几回、天际识归舟。争知我，倚栏杆处，正恁凝愁！<h3 id="行内图片标签inlineImg"><a href="#行内图片标签inlineImg" class="headerlink" title="行内图片标签inlineImg"></a>行内图片标签inlineImg</h3><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">计算机学生专属发型 &#123;% inlineImg https://img.pushihao.com/typora/202505290843430.jpg 70px %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><p>计算机学生专属发型 <img class="inline-img" src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202505290843430.jpg" style="height:70px" /></p><h3 id="链接卡片标签flink"><a href="#链接卡片标签flink" class="headerlink" title="链接卡片标签flink"></a>链接卡片标签flink</h3><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&#123;% flink %&#125;</span><br><span class="line"><span class="bullet">-</span> class<span class="emphasis">_name: 友情链接</span></span><br><span class="line"><span class="emphasis">  class_</span>desc: 那些值得关注的网站~</span><br><span class="line">  link<span class="emphasis">_list:</span></span><br><span class="line"><span class="emphasis">    - name: 披萨盒</span></span><br><span class="line"><span class="emphasis">      link: https://blog.pushihao.com</span></span><br><span class="line"><span class="emphasis">      avatar: /img/avatar.webp</span></span><br><span class="line"><span class="emphasis">      descr: 热水比冷水更快结冰</span></span><br><span class="line"><span class="emphasis">    - name: Hexo</span></span><br><span class="line"><span class="emphasis">      link: https://hexo.io/zh-cn/</span></span><br><span class="line"><span class="emphasis">      avatar: https://d33wubrfki0l68.cloudfront.net/6657ba50e702d84afb32fe846bed54fba1a77add/827ae/logo.svg</span></span><br><span class="line"><span class="emphasis">      descr: 快速、简单且强大的博客框架</span></span><br><span class="line"><span class="emphasis">- class_</span>name: 常用网站</span><br><span class="line">  class<span class="emphasis">_desc: 日常学习必用~</span></span><br><span class="line"><span class="emphasis">  link_</span>list:</span><br><span class="line"><span class="bullet">    -</span> name: Google</span><br><span class="line"><span class="code">      link: https://www.google.com</span></span><br><span class="line"><span class="code">      avatar: /img/icon/google.ico</span></span><br><span class="line"><span class="code">      descr: 搜索平台</span></span><br><span class="line"><span class="code">    - name: Github</span></span><br><span class="line"><span class="code">      link: https://www.github.com</span></span><br><span class="line"><span class="code">      avatar: /img/icon/github.ico</span></span><br><span class="line"><span class="code">      descr: 全球最大的同性交友网站</span></span><br><span class="line"><span class="code">&#123;% endflink %&#125;</span></span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="flink"><div class="flink-name">友情链接</div><div class="flink-desc">那些值得关注的网站~</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://blog.pushihao.com" title="披萨盒" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="/img/loading.gif" data-lazy-src="/img/avatar.webp" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="披萨盒" />          </div>          <div class="flink-item-name">披萨盒</div>          <div class="flink-item-desc" title="热水比冷水更快结冰">热水比冷水更快结冰</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://hexo.io/zh-cn/" title="Hexo" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="/img/loading.gif" data-lazy-src="https://d33wubrfki0l68.cloudfront.net/6657ba50e702d84afb32fe846bed54fba1a77add/827ae/logo.svg" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Hexo" />          </div>          <div class="flink-item-name">Hexo</div>          <div class="flink-item-desc" title="快速、简单且强大的博客框架">快速、简单且强大的博客框架</div>        </a>      </div></div><div class="flink-name">常用网站</div><div class="flink-desc">日常学习必用~</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://www.google.com" title="Google" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="/img/loading.gif" data-lazy-src="/img/icon/google.ico" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Google" />          </div>          <div class="flink-item-name">Google</div>          <div class="flink-item-desc" title="搜索平台">搜索平台</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.github.com" title="Github" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="/img/loading.gif" data-lazy-src="/img/icon/github.ico" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Github" />          </div>          <div class="flink-item-name">Github</div>          <div class="flink-item-desc" title="全球最大的同性交友网站">全球最大的同性交友网站</div>        </a>      </div></div></div><h3 id="引用标签note"><a href="#引用标签note" class="headerlink" title="引用标签note"></a>引用标签note</h3><p>参数说明：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&#123;% note [参数一] [参数二] %&#125;</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">[参数一]: </span><br><span class="line">- 不填</span><br><span class="line">- default</span><br><span class="line">- primary</span><br><span class="line">- success</span><br><span class="line">- info</span><br><span class="line">- warning</span><br><span class="line">- danger</span><br><span class="line">- [颜色] + 图标  如: blue &#x27;fas fa-bullhorn&#x27;</span><br><span class="line"></span><br><span class="line">[参数二]: </span><br><span class="line">- simple</span><br><span class="line">- modern</span><br><span class="line">- flat</span><br><span class="line">- disable</span><br><span class="line">- no-icon</span><br></pre></td></tr></table></figure><p>代码展示：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><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">&#123;% note simple %&#125;</span><br><span class="line">参数一不填，参数二simple效果</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% note default modern %&#125;</span><br><span class="line">参数一默认，参数二modern效果</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% note primary flat %&#125;</span><br><span class="line">参数一primary，参数二flat效果</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% note success disable %&#125;</span><br><span class="line">参数一success，参数二disable效果</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% note info no-icon %&#125;</span><br><span class="line">参数一info，参数二no-icon效果</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% note warning flat %&#125;</span><br><span class="line">参数一warning，参数二flat效果</span><br><span class="line">&#123;% endnote %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% note blue &#x27;fas fa-bullhorn&#x27; flat %&#125;</span><br><span class="line">参数一blue &#x27;fas fa-bullhorn&#x27;，参数二flat效果</span><br><span class="line">&#123;% endnote %&#125;</span><br></pre></td></tr></table></figure><p>效果展示：</p><div class="note simple"><p>参数一不填，参数二simple效果</p></div><div class="note default modern"><p>参数一默认，参数二modern效果</p></div><div class="note primary flat"><p>参数一primary，参数二flat效果</p></div><div class="note success disable flat"><p>参数一success，参数二disable效果</p></div><div class="note info no-icon flat"><p>参数一info，参数二no-icon效果</p></div><div class="note warning flat"><p>参数一warning，参数二flat效果</p></div><div class="note blue icon-padding flat"><i class="note-icon fas fa-bullhorn"></i><p>参数一blue ‘fas fa-bullhorn’，参数二flat效果</p></div><h3 id="画图标签mermaid"><a href="#画图标签mermaid" class="headerlink" title="画图标签mermaid"></a>画图标签mermaid</h3><blockquote><p>通过使用mermaid标签可以绘制Flowchart（流程图）、Sequence Diagram（时序图）、Class Diagram（类别图）、State Diagram（状态图）、Gantt（甘特图）和Pie Chart（饼状图）等，具体可以查看 <a href="https://mermaid-js.github.io/mermaid/#/">memaid文档</a></p></blockquote><p>在使用之前需要修改主题配置文件：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># mermaid</span></span><br><span class="line"><span class="comment"># see https://github.com/mermaid-js/mermaid</span></span><br><span class="line"><span class="attr">mermaid:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="comment"># built-in themes: default/forest/dark/neutral</span></span><br><span class="line">  <span class="attr">theme:</span></span><br><span class="line">    <span class="attr">light:</span> <span class="string">default</span></span><br><span class="line">    <span class="attr">dark:</span> <span class="string">dark</span></span><br></pre></td></tr></table></figure><p>语法：</p><figure class="highlight markdown"><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">&#123;% mermaid %&#125;</span><br><span class="line">内容</span><br><span class="line">&#123;% endmermaid %&#125;</span><br></pre></td></tr></table></figure><br><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这么多语法参数也很琐碎，不可能看一遍就全记下来，随时用随时翻看即可。</p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="技术杂谈" scheme="https://blog.pushihao.com/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/"/>
    
    
    <category term="Hexo" scheme="https://blog.pushihao.com/tags/Hexo/"/>
    
    <category term="配置" scheme="https://blog.pushihao.com/tags/%E9%85%8D%E7%BD%AE/"/>
    
  </entry>
  
  <entry>
    <title>Jupyter设置代码自动补全</title>
    <link href="https://blog.pushihao.com/article/5153ec23.html"/>
    <id>https://blog.pushihao.com/article/5153ec23.html</id>
    <published>2022-06-23T12:05:00.000Z</published>
    <updated>2022-06-23T12:05:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>Jupyter Notebook是我们用Python进行数据分析和机器学习的不二之选，但是Jupyter Notebook默认是不带代码自动补全功能的，我们可以通过安装插件的方式使其具有这个功能</p></blockquote><h2 id="安装模块"><a href="#安装模块" class="headerlink" title="安装模块"></a>安装模块</h2><ol><li>打开 Anaconda Powershell Prompt (Anaconda)</li></ol><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202206232025771.png" alt="image-20220623202510637"> </p><ol start="2"><li>输入<code>pip install jupyter_contrib_nbextensions</code>回车开始安装</li></ol><p>注：此方法默认使用国外的源，如果出现安装失败，参考以下方法</p><ul><li>方法一：使用阿里云的源<code>pip install jupyter_contrib_nbextensions -i https://mirrors.aliyun.com/pypi/simple/</code></li><li>方法二：使用conda包管理器<code>conda install jupyter_contrib_nbextensions</code></li></ul><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><ol><li><p>打开 Anaconda Powershell Prompt (Anaconda)  （方法同上）</p></li><li><p>输入命令<code>jupyter contrib nbextension install --user</code>并回车</p></li><li><p>打开Jupyter Notebook，找到顶部Nbextensions</p></li></ol><p> <img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202206232036306.png" alt="image-20220623203658255"> </p><ol start="4"><li><p>启用相关插件 </p><p> <img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202206232040721.png" alt="image-20220623204013686"></p></li></ol><h2 id="完成"><a href="#完成" class="headerlink" title="完成"></a>完成</h2><p>这次，Jupyter自动补全功能就设置完成了，效果图如下</p><p><img src="/img/loading.gif" data-lazy-src="https://img.pushihao.com/typora/202206232043856.png" alt="image-20220623204342818"> </p>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="编程开发" scheme="https://blog.pushihao.com/categories/%E7%BC%96%E7%A8%8B%E5%BC%80%E5%8F%91/"/>
    
    
    <category term="配置" scheme="https://blog.pushihao.com/tags/%E9%85%8D%E7%BD%AE/"/>
    
    <category term="IDE" scheme="https://blog.pushihao.com/tags/IDE/"/>
    
    <category term="Jupyter" scheme="https://blog.pushihao.com/tags/Jupyter/"/>
    
  </entry>
  
</feed>
