<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>肖林航の博客</title>
  
  
  <link href="https://nuyoah-xlh.github.io/atom.xml" rel="self"/>
  
  <link href="https://nuyoah-xlh.github.io/"/>
  <updated>2024-03-10T13:14:14.084Z</updated>
  <id>https://nuyoah-xlh.github.io/</id>
  
  <author>
    <name>肖林航</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>vue-admin-template实现登录</title>
    <link href="https://nuyoah-xlh.github.io/2023/03/29/vue-admin-template%E5%AE%9E%E7%8E%B0%E7%99%BB%E5%BD%95/"/>
    <id>https://nuyoah-xlh.github.io/2023/03/29/vue-admin-template%E5%AE%9E%E7%8E%B0%E7%99%BB%E5%BD%95/</id>
    <published>2023-03-29T11:22:14.675Z</published>
    <updated>2024-03-10T13:14:14.084Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h2><ul><li>修改<code>src/utils/request.js</code>，以使登录请求正确发送到后端</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; MessageBox, Message &#125; <span class="keyword">from</span> <span class="string">&#x27;element-ui&#x27;</span></span><br><span class="line"><span class="keyword">import</span> store <span class="keyword">from</span> <span class="string">&#x27;@/store&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; getToken &#125; <span class="keyword">from</span> <span class="string">&#x27;@/utils/auth&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// create an axios instance</span></span><br><span class="line"><span class="keyword">const</span> service = axios.create(&#123;</span><br><span class="line">  <span class="attr">baseURL</span>:  <span class="string">&#x27;http://localhost:8201/&#x27;</span>,</span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">5000</span> <span class="comment">// request timeout</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// request interceptor</span></span><br><span class="line">service.interceptors.request.use(</span><br><span class="line">  <span class="function"><span class="params">config</span> =&gt;</span> &#123;</span><br><span class="line"></span><br><span class="line">     config.headers[<span class="string">&#x27;Authorization&#x27;</span>] = getToken()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> config</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// do something with request error</span></span><br><span class="line">    <span class="built_in">console</span>.log(error) <span class="comment">// for debug</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error)</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// response interceptor</span></span><br><span class="line">service.interceptors.response.use(</span><br><span class="line">  <span class="function"><span class="params">response</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> res = response.data</span><br><span class="line"></span><br><span class="line">    <span class="comment">// if the custom code is not 20000, it is judged as an error.</span></span><br><span class="line">    <span class="built_in">console</span>.log(res);</span><br><span class="line">    <span class="keyword">if</span> (res.code !== <span class="number">200</span>) &#123;</span><br><span class="line">      </span><br><span class="line">      Message(&#123;</span><br><span class="line">        <span class="attr">message</span>: res.message || <span class="string">&#x27;Error&#x27;</span>,</span><br><span class="line">        <span class="attr">type</span>: <span class="string">&#x27;error&#x27;</span>,</span><br><span class="line">        <span class="attr">duration</span>: <span class="number">5</span> * <span class="number">1000</span></span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="comment">// 返回401：未登录</span></span><br><span class="line">      <span class="keyword">if</span> (res.code === <span class="number">401</span>) &#123;</span><br><span class="line">        MessageBox.confirm(<span class="string">&#x27;你已被登出，可以取消停留在此页面，或者重新登陆&#x27;</span>, <span class="string">&#x27;确定登出&#x27;</span>, &#123;</span><br><span class="line">          <span class="attr">confirmButtonText</span>: <span class="string">&#x27;重新登陆&#x27;</span>,</span><br><span class="line">          <span class="attr">cancelButtonClass</span>: <span class="string">&#x27;取消&#x27;</span>,</span><br><span class="line">          <span class="attr">type</span>: <span class="string">&#x27;warning&#x27;</span></span><br><span class="line">        &#125;).then(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">          store.dispatch(<span class="string">&#x27;user/resetToken&#x27;</span>).then(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            location.reload() <span class="comment">// 重新实例化router对象，避免bug</span></span><br><span class="line">          &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(<span class="keyword">new</span> <span class="built_in">Error</span>(res.message || <span class="string">&#x27;Error&#x27;</span>))</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> res</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;err&#x27;</span> + error) <span class="comment">// for debug</span></span><br><span class="line">    Message(&#123;</span><br><span class="line">      <span class="attr">message</span>: error.message,</span><br><span class="line">      <span class="attr">type</span>: <span class="string">&#x27;error&#x27;</span>,</span><br><span class="line">      <span class="attr">duration</span>: <span class="number">5</span> * <span class="number">1000</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error)</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> service</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>修改<code>/src/api/user.js</code>文件，使得请求路径完整适配后端</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> request <span class="keyword">from</span> <span class="string">&#x27;@/utils/request&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">login</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> request(&#123;</span><br><span class="line">    <span class="attr">url</span>: <span class="string">&#x27;/user/login&#x27;</span>,</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&#x27;post&#x27;</span>,</span><br><span class="line">    data</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">export</span> <span class="function"><span class="keyword">function</span> <span class="title">getInfo</span>(<span class="params">token</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> request(&#123;</span><br><span class="line">    <span class="attr">url</span>: <span class="string">&#x27;/user/info&#x27;</span>,</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&#x27;get&#x27;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">logout</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> request(&#123;</span><br><span class="line">    <span class="attr">url</span>: <span class="string">&#x27;/user/logout&#x27;</span>,</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&#x27;post&#x27;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>适当修改<code>/src/store/modules/user.js</code>文件，使得接收到的数据能顺利存储，尤其是token数据</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> actions = &#123;</span><br><span class="line">  <span class="comment">// user login</span></span><br><span class="line">  <span class="function"><span class="title">login</span>(<span class="params">&#123; commit &#125;, userInfo</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password &#125; = userInfo</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      login(&#123; <span class="attr">username</span>: username.trim(), <span class="attr">password</span>: password &#125;).then(<span class="function"><span class="params">response</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;111&quot;</span>);</span><br><span class="line">        <span class="built_in">console</span>.log(response);</span><br><span class="line">        <span class="keyword">const</span>  data  = response.data</span><br><span class="line">        <span class="built_in">console</span>.log(data.token);</span><br><span class="line">        commit(<span class="string">&#x27;SET_TOKEN&#x27;</span>, data.token)</span><br><span class="line">        setToken(data.token)</span><br><span class="line"></span><br><span class="line">        resolve()</span><br><span class="line">      &#125;).catch(<span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">        reject(error)</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// get user info</span></span><br><span class="line">  <span class="function"><span class="title">getInfo</span>(<span class="params">&#123; commit, state &#125;</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      getInfo(state.token).then(<span class="function"><span class="params">response</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">const</span> data  = response.data</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;getinfo&quot;</span>);</span><br><span class="line">        <span class="built_in">console</span>.log(data);</span><br><span class="line">        <span class="keyword">if</span> (!data) &#123;</span><br><span class="line">          <span class="keyword">return</span> reject(<span class="string">&#x27;Verification failed, please Login again.&#x27;</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// const &#123; name, avatar &#125; = data</span></span><br><span class="line">        <span class="comment">// roles=data.roles</span></span><br><span class="line">        <span class="comment">// username = data.username</span></span><br><span class="line">        <span class="comment">// avatar=data.avatar</span></span><br><span class="line"></span><br><span class="line">        commit(<span class="string">&#x27;SET_NAME&#x27;</span>, data.username)</span><br><span class="line">        <span class="comment">// commit(&#x27;SET_AVATAR&#x27;, avatar)</span></span><br><span class="line">        resolve(data)</span><br><span class="line">      &#125;).catch(<span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">        reject(error)</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// user logout</span></span><br><span class="line">  <span class="function"><span class="title">logout</span>(<span class="params">&#123; commit, state &#125;</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      logout(state.token).then(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        removeToken() <span class="comment">// must remove  token  first</span></span><br><span class="line">        resetRouter()</span><br><span class="line">        commit(<span class="string">&#x27;RESET_STATE&#x27;</span>)</span><br><span class="line">        resolve()</span><br><span class="line">      &#125;).catch(<span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">        reject(error)</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><ul><li>在<code>main.js</code>文件中，设置请求头的token</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; getToken &#125; <span class="keyword">from</span> <span class="string">&#x27;@/utils/auth&#x27;</span></span><br><span class="line">axios.interceptors.request.use(<span class="function"><span class="params">config</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// if (store.getters.token) &#123;</span></span><br><span class="line">    config.headers[<span class="string">&#x27;Authorization&#x27;</span>] = getToken()</span><br><span class="line">  <span class="comment">// &#125;</span></span><br><span class="line">  <span class="keyword">return</span> config</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="后端"><a href="#后端" class="headerlink" title="后端"></a>后端</h2><h3 id="JWT工具类"><a href="#JWT工具类" class="headerlink" title="JWT工具类"></a>JWT工具类</h3><ul><li>导入依赖包</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.auth0<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>java-jwt<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.18.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li>创建工具类</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.util;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.JWT;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.JWTVerifier;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.algorithms.Algorithm;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.exceptions.JWTDecodeException;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.interfaces.DecodedJWT;</span><br><span class="line"><span class="keyword">import</span> com.xlh.pojo.User;</span><br><span class="line"><span class="keyword">import</span> java.io.UnsupportedEncodingException;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JWTUtil</span> </span>&#123;</span><br><span class="line">    <span class="comment">//token有效时长</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> EXPIRE=<span class="number">30</span>*<span class="number">60</span>*<span class="number">1000L</span>;</span><br><span class="line">    <span class="comment">//token的密钥 可自行定义</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String SECRET=<span class="string">&quot;jwt&quot;</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">createToken</span><span class="params">(User user)</span> <span class="keyword">throws</span> UnsupportedEncodingException </span>&#123;</span><br><span class="line">        <span class="comment">//token过期时间</span></span><br><span class="line">        Date date=<span class="keyword">new</span> Date(System.currentTimeMillis()+EXPIRE);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//jwt的header部分</span></span><br><span class="line">        Map&lt;String ,Object&gt;map=<span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;alg&quot;</span>,<span class="string">&quot;HS256&quot;</span>);</span><br><span class="line">        map.put(<span class="string">&quot;typ&quot;</span>,<span class="string">&quot;JWT&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//使用jwt的api生成token</span></span><br><span class="line">        String token= JWT.create()</span><br><span class="line">                .withHeader(map)</span><br><span class="line">                .withClaim(<span class="string">&quot;username&quot;</span>, user.getUsername())<span class="comment">//私有声明</span></span><br><span class="line">                .withExpiresAt(date)<span class="comment">//过期时间</span></span><br><span class="line">                .withIssuedAt(<span class="keyword">new</span> Date())<span class="comment">//签发时间</span></span><br><span class="line">                .sign(Algorithm.HMAC256(SECRET));<span class="comment">//签名</span></span><br><span class="line">        <span class="keyword">return</span> token;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 校验token的有效性</span></span><br><span class="line"><span class="comment">     * 1 token的header和payload是否没改过</span></span><br><span class="line"><span class="comment">     * 2 没有过期</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">verify</span><span class="params">(String token)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//解密</span></span><br><span class="line">            JWTVerifier verifier=JWT.require(Algorithm.HMAC256(SECRET)).build();</span><br><span class="line">            verifier.verify(token);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//无需解密也可以获取token的信息</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">getUsername</span><span class="params">(String token)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            DecodedJWT jwt = JWT.decode(token);</span><br><span class="line">            <span class="keyword">return</span> jwt.getClaim(<span class="string">&quot;username&quot;</span>).asString();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (JWTDecodeException e) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>创建对外界请求的拦截器，以检查token合法性</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.Interceptor;</span><br><span class="line"><span class="keyword">import</span> com.xlh.util.JWTUtil;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.HandlerInterceptor;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletResponse;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JWTInterceptor</span> <span class="keyword">implements</span> <span class="title">HandlerInterceptor</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">preHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">  <span class="comment">// 判断是否是预检请求，是则直接返回</span></span><br><span class="line">       <span class="keyword">if</span> (request.getMethod().equals(<span class="string">&quot;OPTIONS&quot;</span>))&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//从请求头内获取token</span></span><br><span class="line">        String token = request.getHeader(<span class="string">&quot;Authorization&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;token&quot;</span>);</span><br><span class="line">        System.out.println(token);</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="keyword">return</span> JWTUtil.verify(token);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>注册拦截器</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.config;</span><br><span class="line"><span class="keyword">import</span> com.xlh.Interceptor.JWTInterceptor;</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.servlet.config.annotation.InterceptorRegistry;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.WebMvcConfigurer;</span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InterceptorConfig</span> <span class="keyword">implements</span> <span class="title">WebMvcConfigurer</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> </span>&#123;</span><br><span class="line">        registry.addInterceptor(<span class="keyword">new</span> JWTInterceptor())</span><br><span class="line">                .addPathPatterns(<span class="string">&quot;/**&quot;</span>)</span><br><span class="line">                .excludePathPatterns(<span class="string">&quot;/user/login&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Mapper实现"><a href="#Mapper实现" class="headerlink" title="Mapper实现"></a>Mapper实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mapper;</span><br><span class="line"><span class="keyword">import</span> com.xlh.pojo.User;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Mapper;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Select;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Repository;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="meta">@Repository</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">LoginMapper</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Select(&quot;select id,username,password from user where username=#&#123;username&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> User <span class="title">getUserByUserName</span><span class="params">(String username)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Service实现"><a href="#Service实现" class="headerlink" title="Service实现"></a>Service实现</h3><ul><li>接口创建</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">package</span> com.xlh.service;</span><br><span class="line"><span class="keyword">import</span> com.xlh.pojo.User;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">LoginService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> User <span class="title">getUser</span><span class="params">(String username)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>接口实现</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.service.impl;</span><br><span class="line"><span class="keyword">import</span> com.xlh.mapper.LoginMapper;</span><br><span class="line"><span class="keyword">import</span> com.xlh.pojo.User;</span><br><span class="line"><span class="keyword">import</span> com.xlh.service.LoginService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginServiceImpl</span> <span class="keyword">implements</span> <span class="title">LoginService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> LoginMapper loginMapper;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> User <span class="title">getUser</span><span class="params">(String username)</span> </span>&#123;</span><br><span class="line">        User user=loginMapper.getUserByUserName(username);</span><br><span class="line">        <span class="comment">//未查到用户</span></span><br><span class="line">        <span class="keyword">if</span>(user==<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> user;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Controller实现"><a href="#Controller实现" class="headerlink" title="Controller实现"></a>Controller实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSONObject;</span><br><span class="line"><span class="keyword">import</span> com.xlh.common.api.CommonResult;</span><br><span class="line"><span class="keyword">import</span> com.xlh.pojo.User;</span><br><span class="line"><span class="keyword">import</span> com.xlh.service.LoginService;</span><br><span class="line"><span class="keyword">import</span> com.xlh.util.JWTUtil;</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.*;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/user&quot;)</span></span><br><span class="line"><span class="meta">@CrossOrigin</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> LoginService loginService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(method = RequestMethod.POST, path=&quot;/login&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> CommonResult <span class="title">login</span><span class="params">(<span class="meta">@RequestBody</span> String requestBody)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        JSONObject jsonObject = JSON.parseObject(requestBody);</span><br><span class="line">        String name=jsonObject.getString(<span class="string">&quot;username&quot;</span>);</span><br><span class="line">        String password=jsonObject.getString(<span class="string">&quot;password&quot;</span>);</span><br><span class="line">        User user=loginService.getUser(name);</span><br><span class="line">        System.out.println(user);</span><br><span class="line">        <span class="comment">//登录失败</span></span><br><span class="line">        <span class="keyword">if</span>(user==<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> CommonResult.success(<span class="number">200</span>,<span class="string">&quot;登录失败&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(user.getPassword().equals(password))&#123;</span><br><span class="line">                HashMap&lt;String, String&gt; map=<span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">                String token= JWTUtil.createToken(user);</span><br><span class="line">                map.put(<span class="string">&quot;token&quot;</span>,token);</span><br><span class="line">                <span class="keyword">return</span> CommonResult.success(<span class="number">200</span>,<span class="string">&quot;登录成功&quot;</span>,map);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span>&#123;</span><br><span class="line">                <span class="keyword">return</span> CommonResult.success(<span class="number">200</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"></span><br><span class="line">    <span class="meta">@RequestMapping(method = RequestMethod.GET,value = &quot;/info&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> CommonResult <span class="title">info</span><span class="params">(HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">        String token = request.getHeader(<span class="string">&quot;Authorization&quot;</span>);</span><br><span class="line">        HashMap&lt;String, String&gt; responseData = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        responseData.put(<span class="string">&quot;roles&quot;</span>,<span class="string">&quot;admin&quot;</span>);</span><br><span class="line">        String username=JWTUtil.getUsername(token);</span><br><span class="line">        responseData.put(<span class="string">&quot;username&quot;</span>,username);</span><br><span class="line">        responseData.put(<span class="string">&quot;avatar&quot;</span>,<span class="string">&quot;&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> CommonResult.success(<span class="number">200</span>,<span class="string">&quot;获取成功&quot;</span>,responseData);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(method = RequestMethod.POST,value = &quot;/logout&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> CommonResult <span class="title">logout</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> CommonResult.success(<span class="string">&quot;ok&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><ul><li>在加入token验证后，可能会出现前端跨域的报错，设置相关跨域配置后依然无法解决，查看浏览器网络请求，发现在请求发送时，浏览器会先发送一个预检请求，跨域报错就出在这个地方。解决方法是在后端，判断是否是预检请求，是则直接返回，具体代码见上文。</li></ul>]]></content>
    
    
    <summary type="html">本文中，使用Springboot作为后端，vue-admin-template作为前端框架，基于Jwt简单实现了登录/注销的前后端交互。</summary>
    
    
    
    <category term="Git/GitHub" scheme="https://nuyoah-xlh.github.io/categories/Git-GitHub/"/>
    
    
    <category term="Git/GitHub" scheme="https://nuyoah-xlh.github.io/tags/Git-GitHub/"/>
    
  </entry>
  
  <entry>
    <title>Hadoop入门</title>
    <link href="https://nuyoah-xlh.github.io/2022/10/20/Hadoop%E5%85%A5%E9%97%A8/"/>
    <id>https://nuyoah-xlh.github.io/2022/10/20/Hadoop%E5%85%A5%E9%97%A8/</id>
    <published>2022-10-20T14:40:44.201Z</published>
    <updated>2024-03-10T13:14:14.081Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>​    Hadoop是一款开源软件，允许用户使用简单的编程模型实现跨机器集群对海量数据进行分布式计算处理。</p><p><strong>核心组件：</strong></p><ul><li>Hadoop HDFS（分布式文件存储系统）：解决海量数据存储</li><li>Hadoop YARN（集群资源管理和任务调度框架）：解决资源任务调度</li><li>Hadoop MapReduce（分布式计算框架）：解决海量数据计算</li></ul><p><strong>现状：</strong></p><ul><li>HDFS作为分布式文件存储系统，处在生态圈的底层与核心地位；</li><li>YARN作为分布式通用的集群资源管理系统和任务调度平台，支撑各种计算引擎运行，保证了Hadoop地位；</li><li>MapReduce作为大数据生态圈第一代分布式计算引擎，由于自身设计的模型所产生的弊端，导致企业一线几乎不再直接使用MapReduce进行编程处理，但是很多软件的底层依然在使用MapReduce引擎来处理数据。</li></ul><p><strong>发行版本：</strong></p><ul><li>Apache开源社区版本：<a href="https://hadoop.apache.org/">https://hadoop.apache.org/</a></li></ul><h2 id="Hadoop集群搭建"><a href="#Hadoop集群搭建" class="headerlink" title="Hadoop集群搭建"></a>Hadoop集群搭建</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><ul><li>Hadoop集群包括两个集群：HDFS集群、YARN集群</li><li>两个集群逻辑上分离、通常物理上在一起</li><li>两个集群都是标准的主从架构集群</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-21_16-57-34.jpg" alt="0.jpg"></p><h3 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h3><ul><li>在主机上执行<code>start-all.sh</code>，并用jps查看java进程</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-23_20-49-38.jpg" alt="0.jpg"></p><ul><li>可在两个ui界面管理<ul><li>HDFS集群：<a href="http://namenode_host:9870/">http://namenode_host:9870</a></li><li>YARN集群：<a href="http://resourcemanager_host:8088/">http://resourcemanager_host:8088</a></li></ul></li></ul><h3 id="Hadoop体验"><a href="#Hadoop体验" class="headerlink" title="Hadoop体验"></a>Hadoop体验</h3><ul><li>shell命令<ul><li><code>hadoop fs -mkdir /itcast</code>：创建文件夹</li><li><code>hadoop fs -put zookeeper.out /itcast</code> ：上传文件</li></ul></li><li>UI页面</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-23_21-45-11.jpg" alt="0.jpg"></p><h2 id="HDFS"><a href="#HDFS" class="headerlink" title="HDFS"></a>HDFS</h2><h3 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h3><ul><li>HDFS，意为：Hadoop分布式文件系统；</li><li>HDFS主要是解决大数据如何存储问题的。分布式意味着是HDFS是横跨在多台计算机上的存储系统；</li><li>高度容错，非常适于存储大型数据(比如TB 和PB)</li><li>HDFS使用多台计算机存储文件, 并且提供统一的访问接口, 像是访问一个普通文件系统一样使用分布式文件系统</li></ul><h3 id="设计目标"><a href="#设计目标" class="headerlink" title="设计目标"></a>设计目标</h3><ul><li>硬件故障是常态，HDFS可能有成百上千的服务器组成，每一个组件都有可能出现故障。因此故障检测和自动快速恢复是HDFS的核心架构目标</li><li>HDFS上的应用主要是以流式读取数据。HDFS被设计成用于批处理，而不是用户交互式的。相较于数据访问的反应时间，更注重数据访问的高吞吐量</li><li>支持大文件</li><li>大部分文件：一个文件一旦创建、写入、关闭之后就不需要修改</li><li>可从一个平台轻松移植到另一个平台</li><li>应用场景：大文件、数据流式访问、一次写入多次读取、低成本</li><li>不适用场景：小文件、频繁任意修改、数据交互式访问</li></ul><h3 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h3><ul><li>HDFS集群是标准的master/slave主从架构集群</li><li>一般一个HDFS集群是有一个Namenode和一定数目的Datanode组成</li><li>Namenode是HDFS主节点，Datanode是HDFS从节点，两种角色各司其职，共同协调完成分布式的文件存储服务</li><li>HDFS中的文件在物理上是分块存储的，默认大小是128M，不足128M则本身就是一块</li><li>文件的所有块都会有副本，默认值是3份（包括自身）</li><li>元数据管理<ul><li>Namenode管理的元数据具有两种类型：<ul><li>文件自身属性信息：文件名称、权限，修改时间，文件大小，复制因子，数据块大小</li><li>文件块位置映射信息：记录文件块和DataNode之间的映射信息，即哪个块位于哪个节点上</li></ul></li></ul></li></ul><h3 id="常用操作"><a href="#常用操作" class="headerlink" title="常用操作"></a>常用操作</h3><p>​    一般可用UI界面和shell命令操作HDFS，常用命令如下：</p><ul><li><code>hadoop fs -mkdir /name：</code>创建目录</li><li><code>hadoop fs -put ...</code>：上传文件</li><li><code>hadoop fs -get ...</code>：下载文件</li></ul><h3 id="角色及职责"><a href="#角色及职责" class="headerlink" title="角色及职责"></a>角色及职责</h3><ul><li>NameNode<ul><li>是Hadoop分布式文件系统的核心，架构中的主角色</li><li>NameNode维护和管理文件系统元数据，包括名称空间目录树结构、文件和块的位置信息、访问权限等信息</li><li>NameNode成为了访问HDFS的唯一入口</li><li>仅存储HDFS的元数据,不存储实际数据</li><li>不持久化存储每个文件中各个块所在的datanode的位置信息。开机时从datenode重建</li></ul></li><li>DataNode<ul><li>是Hadoop HDFS中的从角色，负责具体的数据块存储</li><li>DataNode的数量决定了HDFS集群的整体数据存储能力。通过和NameNode配合维护着数据块</li><li>启动时，会将自己注册到NameNode并汇报自己负责持有的块列表</li></ul></li><li>secondarynamenode<ul><li>主角色辅助角色</li><li>主要是帮助主角色进行元数据文件的合并动作</li></ul></li></ul><h2 id="YARN"><a href="#YARN" class="headerlink" title="YARN"></a>YARN</h2><h3 id="简介-2"><a href="#简介-2" class="headerlink" title="简介"></a>简介</h3><ul><li><p>是一个通用资源管理系统和调度平台，可为上层应用提供统一的资源管理和调度</p></li><li><p>功能：</p><ul><li>资源管理系统：集群的硬件资源，和程序运行相关，比如内存、CPU等</li><li>调度平台：多个程序同时申请计算资源如何分配，调度的规则</li><li>理论上支持各种计算程序</li></ul></li><li><p>可以把Hadoop YARN理解为相当于一个分布式的操作系统平台，而MapReduce等计算程序则相当于运行于操作系统之上的应用程序，YARN为这些程序提供运算所需的资源</p></li></ul><h3 id="三大组件"><a href="#三大组件" class="headerlink" title="三大组件"></a>三大组件</h3><ul><li>ResourceManager（RM）<ul><li>YARN集群中的主角色，决定系统中所有应用程序之间资源分配的最终权限，即最终仲裁者</li><li>接收用户的作业提交，并通过NM分配、管理各个机器上的计算资源</li></ul></li><li>NodeManager（NM）<ul><li>YARN中的从角色，一台机器上一个，负责管理本机器上的计算资源</li><li>根据RM命令，启动Container容器、监视容器的资源使用情况。并且向RM主角色汇报资源使用情况</li></ul></li><li>ApplicationMaster（AM）<ul><li>用户提交的每个应用程序均包含一个AM</li><li>负责程序内部各阶段的资源申请，监督程序的执行情况</li></ul></li></ul><h3 id="整体流程"><a href="#整体流程" class="headerlink" title="整体流程"></a>整体流程</h3><ul><li>第一个阶段是客户端申请资源启动运行本次程序的ApplicationMaster</li><li>第二个阶段是由ApplicationMaster根据本次程序内部具体情况，为它申请资源，并监控它的整个运行过程，直到运行完成。</li></ul><h3 id="调度器策略"><a href="#调度器策略" class="headerlink" title="调度器策略"></a>调度器策略</h3><ul><li>FIFO Scheduler（先进先出调度器）</li><li>Capacity Scheduler（容量调度器，Apache版本YARN默认使用该策略）：可以理解成一个个的资源队列，这个资源队列是用户自己去分配的。队列内部又可以垂直划分，这样一个组织内部的多个成员就可以共享这个队列资源了，在一个队列内部，资源的调度是采用的是先进先出(FIFO)策略。简单通俗点来说，就是一个个队列有独立的资源，队列的结构和资源是可以进行配置的。</li><li>Fair Scheduler（公平调度器）：为所有的应用分配公平的资源</li></ul><h2 id="数据仓库"><a href="#数据仓库" class="headerlink" title="数据仓库"></a>数据仓库</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><ul><li>是一个用于存储、分析、报告的数据系统</li><li>目的是构建面向分析的集成化数据环境，分析结果为企业提供决策支持</li><li>数据仓库本身并不“生产”任何数据，其数据来源于不同外部系统</li><li>数据仓库自身也不需要“消费”任何的数据，其结果开放给各个外部应用使用</li><li>为了分析数据而来，分析结果给企业决策提供支撑</li><li>特征：<ul><li>面向主题、集成性、非易失性、时变性</li></ul></li></ul><h2 id="Apache-Hive"><a href="#Apache-Hive" class="headerlink" title="Apache Hive"></a>Apache Hive</h2><h3 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h3><p>​    Apache Hive是一款建立在Hadoop之上的开源数据仓库系统，可以将存储在Hadoop文件中的结构化、半结构化数据文件映射为一张数据库表，基于表提供了一种类似SQL的查询模型，称为Hive查询语言（HQL），用于访问和分析存储在Hadoop文件中的大型数据集。</p><p>​    Hive核心是将HQL转换为MapReduce程序，然后将程序提交到Hadoop群集执行。</p><ul><li>Hive利用HDFS存储数据，利用MapReduce查询分析数据。</li><li>Hive的最大的魅力在于用户专注于编写HQL，Hive帮您转换成为MapReduce程序完成对数据的分析</li><li>在hive中能够写sql处理的前提是针对表，而不是针对文件，因此需要将文件和表之间的对应关系描述记录清楚。映射信息专业的叫法称之为元数据信息</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-24_20-47-46.jpg" alt="0.jpg"></p><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>​    元数据，又称中介数据、中继数据，为描述数据的数据，主要是描述数据属性的信息，用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。元数据存储在关系型数据库中。</p><h4 id="Hive-Metastore"><a href="#Hive-Metastore" class="headerlink" title="Hive Metastore"></a>Hive Metastore</h4><ul><li>Metastore即元数据服务。Metastore服务的作用是管理metadata元数据，对外暴露服务地址，让各种客户端通过连接metastore服务，由metastore再去连接MySQL数据库来存取元数据。且不需要知道数据库的密码等信息，更安全。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-24_20-52-02.jpg" alt="0.jpg"></p><ul><li>前台启动：<code>[root@node1 ~]# /export/server/apache-hive-3.1.2-bin/bin/hive --service hiveserver2</code></li><li>后台启动：<code>[root@node1 ~]# nohup /export/server/apache-hive-3.1.2-bin/bin/hive --service metastore &amp;</code></li><li>客户端，两种，推荐第二代</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-25_16-54-00.jpg" alt="0.jpg"></p><h4 id="bin-beeline客户端使用"><a href="#bin-beeline客户端使用" class="headerlink" title="bin/beeline客户端使用"></a>bin/beeline客户端使用</h4><ul><li>启动第二代客户端</li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nohup /<span class="built_in">export</span>/server/apache-hive-3.1.2-bin/bin/hive --service metastore &amp;</span><br><span class="line">nohup /<span class="built_in">export</span>/server/apache-hive-3.1.2-bin/bin/hive --service hiveserver2 &amp;</span><br></pre></td></tr></table></figure><ul><li>拷贝node1安装包到beeline客户端机器上（node3）:<code>scp -r /export/server/apache-hive-3.1.2-bin/ node3:/export/server/</code></li><li>在node3启动客户端：<code>[root@node3 server]# /export/server/apache-hive-3.1.2-bin/bin/beeline</code></li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">beeline&gt; ! connect jdbc:hive2://node1:10000</span><br><span class="line">Connecting to jdbc:hive2://node1:10000</span><br><span class="line">Enter username <span class="keyword">for</span> jdbc:hive2://node1:10000: root</span><br><span class="line">Enter password <span class="keyword">for</span> jdbc:hive2://node1:10000: </span><br><span class="line">Connected to: Apache Hive (version 3.1.2)</span><br><span class="line">Driver: Hive JDBC (version 3.1.2)</span><br><span class="line">Transaction isolation: TRANSACTION_REPEATABLE_READ</span><br><span class="line">0: jdbc:hive2://node1:10000&gt; </span><br></pre></td></tr></table></figure><ul><li><strong>一般可使用DataGrip连接hive</strong></li></ul><h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><ul><li>默认分隔符：’\001’</li><li>row format delimited fields terminated by 指定字段之间的分隔符</li><li>在Hive中，默认的数据库叫做default，存储数据位置位于HDFS的/user/hive/warehouse下</li><li>用户自己创建的数据库存储位置是/user/hive/warehouse/database_name.db下</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-25_18-09-42.jpg" alt="0.jpg"></p><ul><li>只有把数据文件移动到对应的表文件夹下面，Hive才能映射解析成功;</li></ul>]]></content>
    
    
    <summary type="html">本文是Git所需要的基本命令汇总，包括创建版本库到版本回退、修改、删除等基本知识点。</summary>
    
    
    
    <category term="Git/GitHub" scheme="https://nuyoah-xlh.github.io/categories/Git-GitHub/"/>
    
    
    <category term="Git/GitHub" scheme="https://nuyoah-xlh.github.io/tags/Git-GitHub/"/>
    
  </entry>
  
  <entry>
    <title>Hibernate Validator参数校验&amp;自定义注解</title>
    <link href="https://nuyoah-xlh.github.io/2022/10/20/Hibernate%20Validator%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C/"/>
    <id>https://nuyoah-xlh.github.io/2022/10/20/Hibernate%20Validator%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C/</id>
    <published>2022-10-20T11:14:09.881Z</published>
    <updated>2024-03-10T13:14:14.082Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>​    后端常常会需要对参数进行校验，这里提供两种处理校验逻辑的方式。一种是使用Hibernate Validator来处理，另一种是使用全局异常来处理。对于前者，还可以使用自定义注解进行参数校验。</p><h2 id="Hibernate-Validator"><a href="#Hibernate-Validator" class="headerlink" title="Hibernate Validator"></a>Hibernate Validator</h2><p>​    Hibernate Validator是 SpringBoot 内置的校验框架，只要集成了 SpringBoot 就自动集成了它，我们可以通过在对象上面使用它提供的注解来完成参数校验。</p><h3 id="常用注解"><a href="#常用注解" class="headerlink" title="常用注解"></a>常用注解</h3><ul><li>@Null：被注释的属性必须为null；</li><li>@NotNull：被注释的属性不能为null；</li><li>@AssertTrue：被注释的属性必须为true；</li><li>@AssertFalse：被注释的属性必须为false；</li><li>@Min：被注释的属性必须大于等于其value值；</li><li>@Max：被注释的属性必须小于等于其value值；</li><li>@Size：被注释的属性必须在其min和max值之间；</li><li>@Pattern：被注释的属性必须符合其regexp所定义的正则表达式；</li><li>@NotBlank：被注释的字符串不能为空字符串；</li><li>@NotEmpty：被注释的属性不能为空；</li><li>@Email：被注释的属性必须符合邮箱格式。</li></ul><h3 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h3><ul><li>实体类</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;用户名&quot;, required = true)</span></span><br><span class="line">    <span class="meta">@NotEmpty(message = &quot;用户名不为空&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;密码&quot;, required = true)</span></span><br><span class="line">    <span class="meta">@NotEmpty(message = &quot;密码不为空&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;邮箱&quot;, required = true)</span></span><br><span class="line">    <span class="meta">@Email(message = &quot;邮箱格式不合法&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String email;</span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;是否进行显示&quot;)</span></span><br><span class="line">    <span class="meta">@FlagValidator(value = &#123;&quot;0&quot;,&quot;1&quot;&#125;, message = &quot;显示状态不正确&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer showStatus;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>添加@Validated注解，并注入一个BindingResult参数</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/test&quot;)</span></span><br><span class="line">publicclass TestController &#123;</span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/t0&quot;, method = RequestMethod.POST)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">create</span><span class="params">(<span class="meta">@Validated</span> <span class="meta">@RequestBody</span> User user, BindingResult result)</span> </span>&#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>然后在整个Controller层创建一个切面，在其环绕通知中获取到注入的BindingResult对象，通过hasErrors方法判断校验是否通过，如果有错误信息直接返回错误信息，验证通过则放行；</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//在controller类的方法中，对参数通过HibernateValidator注解校验，然后利用aop通过此类对校验错误的进行整理输出日志</span></span><br><span class="line"><span class="comment">// 代理</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="comment">//组件，该类和被代理的类都需要有</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="comment">//优先级</span></span><br><span class="line"><span class="meta">@Order(2)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BindingResultAspect</span> </span>&#123;</span><br><span class="line">    <span class="comment">//切入点为controller所有方法</span></span><br><span class="line">    <span class="meta">@Pointcut(&quot;execution(public * cn.xlh.controller.*.*(..))&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">BindingResult</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//环绕通知</span></span><br><span class="line">    <span class="meta">@Around(&quot;BindingResult()&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">doAround</span><span class="params">(ProceedingJoinPoint joinPoint)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">        <span class="comment">//获取切入方法的所有参数</span></span><br><span class="line">        Object[] args = joinPoint.getArgs();</span><br><span class="line">        <span class="keyword">for</span> (Object arg : args) &#123;</span><br><span class="line">            <span class="comment">//参数被HibernateValidator注解校验</span></span><br><span class="line">            <span class="keyword">if</span> (arg <span class="keyword">instanceof</span> BindingResult) &#123;</span><br><span class="line">                <span class="comment">//判断是否出错</span></span><br><span class="line">                ...</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> joinPoint.proceed();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="自定义注解"><a href="#自定义注解" class="headerlink" title="自定义注解"></a>自定义注解</h3><p>​    有时候框架提供的校验注解并不能满足我们的需要，此时我们就需要自定义校验注解。如User类的参数showStatus，我们希望它只能是0或者1，不能是其他数字，此时可以使用自定义注解来实现该功能。</p><ul><li>首先自定义一个校验注解类FlagValidator</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Target(&#123;ElementType.FIELD,ElementType.PARAMETER&#125;)</span></span><br><span class="line"><span class="meta">@Constraint(validatedBy = FlagValidatorClass.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> FlagValidator &#123;</span><br><span class="line">    String[] value() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">    <span class="function">String <span class="title">message</span><span class="params">()</span> <span class="keyword">default</span> &quot;flag is not found&quot;</span>;</span><br><span class="line">    Class&lt;?&gt;[] groups() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">    Class&lt;? extends Payload&gt;[] payload() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>然后创建FlagValidatorClass作为校验逻辑的具体实现类，实现ConstraintValidator接口，这里需要指定两个泛型参数，第一个需要指定为你自定义的校验注解类，第二个指定为你要校验属性的类型</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FlagValidatorClass</span> <span class="keyword">implements</span> <span class="title">ConstraintValidator</span>&lt;<span class="title">FlagValidator</span>,<span class="title">Integer</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String[] values;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initialize</span><span class="params">(FlagValidator flagValidator)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.values = flagValidator.value();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isValid</span><span class="params">(Integer value, ConstraintValidatorContext constraintValidatorContext)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">boolean</span> isValid = <span class="keyword">false</span>;</span><br><span class="line">        <span class="keyword">if</span>(value==<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="comment">//当状态为空时使用默认值</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;values.length;i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(values[i].equals(String.valueOf(value)))&#123;</span><br><span class="line">                isValid = <span class="keyword">true</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> isValid;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>使用注解</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;是否进行显示&quot;)</span></span><br><span class="line">    <span class="meta">@FlagValidator(value = &#123;&quot;0&quot;,&quot;1&quot;&#125;, message = &quot;显示状态不正确&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer showStatus;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">Hibernate Validator是SpringBoot内置的校验框架，我们可以通过在对象上面使用它提供的注解来完成参数校验。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>Spring-Security入门</title>
    <link href="https://nuyoah-xlh.github.io/2022/10/16/Spring-Security%E5%85%A5%E9%97%A8/"/>
    <id>https://nuyoah-xlh.github.io/2022/10/16/Spring-Security%E5%85%A5%E9%97%A8/</id>
    <published>2022-10-16T10:43:21.162Z</published>
    <updated>2022-10-16T16:05:24.832Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="认证和授权"><a href="#认证和授权" class="headerlink" title="认证和授权"></a>认证和授权</h2><h3 id="认证（authentication）"><a href="#认证（authentication）" class="headerlink" title="认证（authentication）"></a>认证（authentication）</h3><p>​    认证意味着确认你自己的身份，是关于验证你的凭据，如用户名/邮箱和密码，以验证访问者的身份。系统确定你是否就是你所说的使用凭据。常见的认证方式有：</p><ul><li>手机和短信验证码认证</li><li>用户名密码认证</li><li>邮箱和邮件验证码认证</li></ul><h3 id="授权（authorization）"><a href="#授权（authorization）" class="headerlink" title="授权（authorization）"></a>授权（authorization）</h3><p>​    授权意味着授予对系统的访问权限。授权发生在系统完成身份认证之后，最终会授予你访问资源（如信息，文件，数据库，资金，位置，几乎任何内容）的完全权限。简单来说，授权决定了你访问系统的能力以及达到的程度。</p><p>​    授权是确定经过身份验证的用户是否可以访问特定资源的过程。就像给予某人官方许可做某事或任何事情。</p><h2 id="Spring-Security简介"><a href="#Spring-Security简介" class="headerlink" title="Spring Security简介"></a>Spring Security简介</h2><p>​    Spring Security是 Spring 家族中的一个安全管理框架，是一个功能强大且高度可定制的身份验证和访问控制框架。认证和授权就是Spring Security作为安全框架的核心功能。</p><p><strong>官方文档地址：</strong><a href="https://spring.io/projects/spring-security/#learn">https://spring.io/projects/spring-security/#learn</a></p><h2 id="小试牛刀"><a href="#小试牛刀" class="headerlink" title="小试牛刀"></a>小试牛刀</h2><h3 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</h3><p>​    创建一个 Spring Boot 的 web 项目，并导入部分依赖，这里为方便测试，直接利用 Thymleaf 进行前后端交互。pom文件如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</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>2.7.4<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">relativePath</span>/&gt;</span> <span class="comment">&lt;!-- lookup parent from repository --&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">groupId</span>&gt;</span>com.demo<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>spsc<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>spsc<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>Demo project for Spring Boot<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>1.8<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--web--&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;!--thyneleof模板--&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.thymeleaf<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>thymeleaf-spring5<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.thymeleaf.extras<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>thymeleaf-extras-java8time<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="comment">&lt;!--spring security模块--&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-security<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><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><h3 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h3><p>​    前端展示页面较为简单，结构如下（level1/2/3分别对应vip1/2/3，login为自定义登录页，index为首页）：</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-16_23-44-33.jpg" alt="20201019172422525.jpg"></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-16_23-46-30.jpg" alt="20201019172422525.jpg"></p><h3 id="Spring-Security配置"><a href="#Spring-Security配置" class="headerlink" title="Spring Security配置"></a>Spring Security配置</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.demo.spsc.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;</span><br><span class="line"></span><br><span class="line"><span class="meta">@EnableWebSecurity</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecurityConfig</span> <span class="keyword">extends</span> <span class="title">WebSecurityConfigurerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//授权</span></span><br><span class="line">    <span class="comment">//链式编程</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//首页所有人都能访问，功能页只对有权限的用户开放</span></span><br><span class="line">        <span class="comment">//请求授权的规则，角色等</span></span><br><span class="line">        http.authorizeHttpRequests()</span><br><span class="line">                .antMatchers(<span class="string">&quot;/&quot;</span>).permitAll()</span><br><span class="line">                .antMatchers(<span class="string">&quot;/level1/**&quot;</span>).hasRole(<span class="string">&quot;vip1&quot;</span>)</span><br><span class="line">                .antMatchers(<span class="string">&quot;/level2/**&quot;</span>).hasRole(<span class="string">&quot;vip2&quot;</span>)</span><br><span class="line">                .antMatchers(<span class="string">&quot;/level3/**&quot;</span>).hasRole(<span class="string">&quot;vip3&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//没有权限会默认到登录页，但该页为内部默认登录页，而不是我们自己写的登录页。也可以将该方法用and()拼接到上面的链式编程上</span></span><br><span class="line">        <span class="comment">//可以自定义登录页,前者为前往登录页，后者为登录提交url（与前端对应），参数也需对应，如不对应，也可在下面手动对应</span></span><br><span class="line">        http.formLogin().loginPage(<span class="string">&quot;/toLoginForm&quot;</span>).usernameParameter(<span class="string">&quot;username&quot;</span>).passwordParameter(<span class="string">&quot;password&quot;</span>).loginProcessingUrl(<span class="string">&quot;/login&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//开启注销功能,注销后跳转到首页</span></span><br><span class="line">        http.logout().logoutSuccessUrl(<span class="string">&quot;/&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//开启记住我功能,利用cookie默认保存两周,参数也需和前端对应</span></span><br><span class="line">        http.rememberMe().rememberMeParameter(<span class="string">&quot;remember&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//认证，注意：在springboot2.1以上的版本中，会报错：密码未编码,在下面加入passwordEncoder方法可解决</span></span><br><span class="line">    <span class="comment">//spring5 security5.0+的版本中，新增多种加密算法</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//在内存中进行认证,也可使用jdbc相关方法通过数据库认证</span></span><br><span class="line">        auth.inMemoryAuthentication().passwordEncoder(<span class="keyword">new</span> BCryptPasswordEncoder())</span><br><span class="line">                .withUser(<span class="string">&quot;xlh&quot;</span>).password(<span class="keyword">new</span> BCryptPasswordEncoder().encode(<span class="string">&quot;123456&quot;</span>)).roles(<span class="string">&quot;vip1&quot;</span>,<span class="string">&quot;vip2&quot;</span>)</span><br><span class="line">                .and()</span><br><span class="line">                .withUser(<span class="string">&quot;root&quot;</span>).password(<span class="keyword">new</span> BCryptPasswordEncoder().encode(<span class="string">&quot;123456&quot;</span>)).roles(<span class="string">&quot;vip1&quot;</span>,<span class="string">&quot;vip2&quot;</span>,<span class="string">&quot;vip3&quot;</span>)</span><br><span class="line">                .and()</span><br><span class="line">                .withUser(<span class="string">&quot;guest&quot;</span>).password(<span class="keyword">new</span> BCryptPasswordEncoder().encode(<span class="string">&quot;123456&quot;</span>)).roles(<span class="string">&quot;vip1&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Controller"><a href="#Controller" class="headerlink" title="Controller"></a>Controller</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.demo.spsc.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RouterController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@RequestMapping(&#123;&quot;/&quot;,&quot;/index&quot;&#125;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">index</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;index&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/toLoginForm&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toLogin</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;views/login&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/level1/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">level1</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> <span class="keyword">int</span> id)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;views/level1/&quot;</span>+id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/level2/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">level2</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> <span class="keyword">int</span> id)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;views/level2/&quot;</span>+id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/level3/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">level3</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> <span class="keyword">int</span> id)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;views/level3/&quot;</span>+id;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h3><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-16_23-50-36.jpg" alt="20201019172422525.jpg"></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-16_23-57-53.jpg" alt="20201019172422525.jpg"></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-16_23-56-46.jpg" alt="20201019172422525.jpg"></p>]]></content>
    
    
    <summary type="html">Spring Security是 Spring 家族中的一个安全管理框架，是一个功能强大且高度可定制的身份验证和访问控制框架。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>解决-Vue项目启动报错</title>
    <link href="https://nuyoah-xlh.github.io/2022/10/09/%E8%A7%A3%E5%86%B3-Vue%E9%A1%B9%E7%9B%AE%E5%90%AF%E5%8A%A8%E6%8A%A5%E9%94%99/"/>
    <id>https://nuyoah-xlh.github.io/2022/10/09/%E8%A7%A3%E5%86%B3-Vue%E9%A1%B9%E7%9B%AE%E5%90%AF%E5%8A%A8%E6%8A%A5%E9%94%99/</id>
    <published>2022-10-09T07:51:09.509Z</published>
    <updated>2022-10-09T14:19:45.841Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="问题记录"><a href="#问题记录" class="headerlink" title="问题记录"></a>问题记录</h2><p>在启动一个 Vue 项目时，出现如下报错：</p><p> <img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-09_15-55-27.jpg"></p><h2 id="问题解决"><a href="#问题解决" class="headerlink" title="问题解决"></a>问题解决</h2><ul><li>可能原因：电脑缺少cmd运行程序的环境变量</li><li>解决方法：在环境变量 Path 中加入 <code>C:\Windows\System32</code> 和 <code>%SystemRoot%\system32;</code>（注意加分号），然后重启电脑；</li></ul><p> <img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-10-09_15-58-13.jpg"></p>]]></content>
    
    
    <summary type="html">解决Vue项目启动时报错的问题，errno:-4058。</summary>
    
    
    
    <category term="解决问题" scheme="https://nuyoah-xlh.github.io/categories/%E8%A7%A3%E5%86%B3%E9%97%AE%E9%A2%98/"/>
    
    
    <category term="解决问题" scheme="https://nuyoah-xlh.github.io/tags/%E8%A7%A3%E5%86%B3%E9%97%AE%E9%A2%98/"/>
    
  </entry>
  
  <entry>
    <title>Vue-Ajax(axios)</title>
    <link href="https://nuyoah-xlh.github.io/2022/10/09/Vue-Ajax(axios)/"/>
    <id>https://nuyoah-xlh.github.io/2022/10/09/Vue-Ajax(axios)/</id>
    <published>2022-10-09T04:40:31.132Z</published>
    <updated>2022-10-09T14:43:30.066Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="GET示例"><a href="#GET示例" class="headerlink" title="GET示例"></a>GET示例</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><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">new</span> Vue(&#123;</span><br><span class="line">  <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">  data () &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">info</span>: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 钩子函数，实例化时触发</span></span><br><span class="line">  mounted () &#123;</span><br><span class="line">    axios</span><br><span class="line">      .get(<span class="string">&#x27;https://www.runoob.com/try/ajax/json_demo.json&#x27;</span>)</span><br><span class="line">      .then(<span class="function"><span class="params">response</span> =&gt;</span> (<span class="built_in">this</span>.info = response))</span><br><span class="line">      .catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123; <span class="comment">// 请求失败处理</span></span><br><span class="line">        <span class="built_in">console</span>.log(error);</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">&lt;script src=<span class="string">&quot;https://unpkg.com/axios/dist/axios.min.js&quot;</span>&gt;&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="POST示例"><a href="#POST示例" class="headerlink" title="POST示例"></a>POST示例</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">new</span> Vue(&#123;</span><br><span class="line">  <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">  data () &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">info</span>: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  mounted () &#123;</span><br><span class="line">    axios</span><br><span class="line">      .post(<span class="string">&#x27;https://www.runoob.com/try/ajax/demo_axios_post.php&#x27;</span>)</span><br><span class="line">      .then(<span class="function"><span class="params">response</span> =&gt;</span> (<span class="built_in">this</span>.info = response))</span><br><span class="line">      .catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123; <span class="comment">// 请求失败处理</span></span><br><span class="line">        <span class="built_in">console</span>.log(error);</span><br><span class="line">      &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="执行多个并发请求"><a href="#执行多个并发请求" class="headerlink" title="执行多个并发请求"></a>执行多个并发请求</h2><ul><li>axios.all 方法接受一个数组作为参数，数组中的每个元素都是一个请求，返回一个 promise 对象，当数组中所有请求均已完成时，执行then方法。</li><li>在then方法中执行了 axios.spread 方法。该方法是接收一个函数作为参数，返回一个新的函数。接收的参数函数的参数是axios.all方法中每个请求返回的响应。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getUserAccount</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> axios.get(<span class="string">&#x27;/user/12345&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getUserPermissions</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> axios.get(<span class="string">&#x27;/user/12345/permissions&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line">axios.all([getUserAccount(), getUserPermissions()])</span><br><span class="line">  .then(axios.spread(<span class="function"><span class="keyword">function</span> (<span class="params">acct, perms</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 两个请求现在都执行完成</span></span><br><span class="line">  &#125;));</span><br><span class="line"><span class="comment">// acct   为方法一 getUserAccount()  的返回值</span></span><br><span class="line"><span class="comment">// perms  为方法二 getUserPermissions() 的返回值</span></span><br></pre></td></tr></table></figure><h2 id="axios-API"><a href="#axios-API" class="headerlink" title="axios  API"></a>axios  API</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 发送 POST 请求</span></span><br><span class="line">axios(&#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&#x27;post&#x27;</span>,</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/user/12345&#x27;</span>,</span><br><span class="line">  <span class="attr">data</span>: &#123;</span><br><span class="line">    <span class="attr">firstName</span>: <span class="string">&#x27;Fred&#x27;</span>,</span><br><span class="line">    <span class="attr">lastName</span>: <span class="string">&#x27;Flintstone&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">//  GET 请求远程图片</span></span><br><span class="line">axios(&#123;</span><br><span class="line">  <span class="attr">method</span>:<span class="string">&#x27;get&#x27;</span>,</span><br><span class="line">  <span class="attr">url</span>:<span class="string">&#x27;https://static.runoob.com/images/runoob-logo.png&#x27;</span>,</span><br><span class="line">  <span class="attr">responseType</span>:<span class="string">&#x27;stream&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line">  .then(<span class="function"><span class="keyword">function</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line">  response.data.pipe(fs.createWriteStream(<span class="string">&#x27;ada_lovelace.jpg&#x27;</span>))</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="创建实例"><a href="#创建实例" class="headerlink" title="创建实例"></a>创建实例</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> instance = axios.create(&#123;</span><br><span class="line">  <span class="attr">baseURL</span>: <span class="string">&#x27;https://some-domain.com/api/&#x27;</span>,</span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">1000</span>,</span><br><span class="line">  <span class="attr">headers</span>: &#123;<span class="string">&#x27;X-Custom-Header&#x27;</span>: <span class="string">&#x27;foobar&#x27;</span>&#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="请求配置项"><a href="#请求配置项" class="headerlink" title="请求配置项"></a>请求配置项</h2><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 只有 url 是必需的,method 默认为 get 方法</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">// `url` 是用于请求的服务器 URL</span></span><br><span class="line">  url: <span class="string">&quot;/user&quot;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `method` 是创建请求时使用的方法</span></span><br><span class="line">  method: <span class="string">&quot;get&quot;</span>, <span class="comment">// 默认是 get</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// `baseURL` 将自动加在 `url` 前面，除非 `url` 是一个绝对 URL。</span></span><br><span class="line">  <span class="comment">// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL</span></span><br><span class="line">  baseURL: <span class="string">&quot;https://some-domain.com/api/&quot;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `transformRequest` 允许在向服务器发送前，修改请求数据</span></span><br><span class="line">  <span class="comment">// 只能用在 &quot;PUT&quot;, &quot;POST&quot; 和 &quot;PATCH&quot; 这几个请求方法</span></span><br><span class="line">  <span class="comment">// 后面数组中的函数必须返回一个字符串，或 ArrayBuffer，或 Stream</span></span><br><span class="line">  transformRequest: [function (data) &#123;</span><br><span class="line">    <span class="comment">// 对 data 进行任意转换处理</span></span><br><span class="line"></span><br><span class="line">    return data;</span><br><span class="line">  &#125;],</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `transformResponse` 在传递给 then/catch 前，允许修改响应数据</span></span><br><span class="line">  transformResponse: [function (data) &#123;</span><br><span class="line">    <span class="comment">// 对 data 进行任意转换处理</span></span><br><span class="line"></span><br><span class="line">    return data;</span><br><span class="line">  &#125;],</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `headers` 是即将被发送的自定义请求头</span></span><br><span class="line">  headers: &#123;<span class="attr">&quot;X-Requested-With&quot;</span>: <span class="string">&quot;XMLHttpRequest&quot;</span>&#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `params` 是即将与请求一起发送的 URL 参数</span></span><br><span class="line">  <span class="comment">// 必须是一个无格式对象(plain object)或 URLSearchParams 对象</span></span><br><span class="line">  params: &#123;</span><br><span class="line">    ID: <span class="number">12345</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `paramsSerializer` 是一个负责 `params` 序列化的函数</span></span><br><span class="line">  <span class="comment">// (e.g. https://www.npmjs.com/package/qs, https://api.jquery.com/jquery.param/)</span></span><br><span class="line">  paramsSerializer: function(params) &#123;</span><br><span class="line">    return Qs.stringify(params, &#123;arrayFormat: <span class="string">&quot;brackets&quot;</span>&#125;)</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `data` 是作为请求主体被发送的数据</span></span><br><span class="line">  <span class="comment">// 只适用于这些请求方法 &quot;PUT&quot;, &quot;POST&quot;, 和 &quot;PATCH&quot;</span></span><br><span class="line">  <span class="comment">// 在没有设置 `transformRequest` 时，必须是以下类型之一：</span></span><br><span class="line">  <span class="comment">// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams</span></span><br><span class="line">  <span class="comment">// - 浏览器专属：FormData, File, Blob</span></span><br><span class="line">  <span class="comment">// - Node 专属： Stream</span></span><br><span class="line">  data: &#123;</span><br><span class="line">    firstName: <span class="string">&quot;Fred&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)</span></span><br><span class="line">  <span class="comment">// 如果请求花费了超过 `timeout` 的时间，请求将被中断</span></span><br><span class="line">  timeout: <span class="number">1000</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `withCredentials` 表示跨域请求时是否需要使用凭证</span></span><br><span class="line">  withCredentials: <span class="literal">false</span>, <span class="comment">// 默认的</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// `adapter` 允许自定义处理请求，以使测试更轻松</span></span><br><span class="line">  <span class="comment">// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).</span></span><br><span class="line">  adapter: function (config) &#123;</span><br><span class="line">    <span class="comment">/* ... */</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `auth` 表示应该使用 HTTP 基础验证，并提供凭据</span></span><br><span class="line">  <span class="comment">// 这将设置一个 `Authorization` 头，覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头</span></span><br><span class="line">  auth: &#123;</span><br><span class="line">    username: <span class="string">&quot;janedoe&quot;</span>,</span><br><span class="line">    password: <span class="string">&quot;s00pers3cret&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `responseType` 表示服务器响应的数据类型，可以是 &quot;arraybuffer&quot;, &quot;blob&quot;, &quot;document&quot;, &quot;json&quot;, &quot;text&quot;, &quot;stream&quot;</span></span><br><span class="line">  responseType: <span class="string">&quot;json&quot;</span>, <span class="comment">// 默认的</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称</span></span><br><span class="line">  xsrfCookieName: <span class="string">&quot;XSRF-TOKEN&quot;</span>, <span class="comment">// default</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称</span></span><br><span class="line">  xsrfHeaderName: <span class="string">&quot;X-XSRF-TOKEN&quot;</span>, <span class="comment">// 默认的</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// `onUploadProgress` 允许为上传处理进度事件</span></span><br><span class="line">  onUploadProgress: function (progressEvent) &#123;</span><br><span class="line">    <span class="comment">// 对原生进度事件的处理</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `onDownloadProgress` 允许为下载处理进度事件</span></span><br><span class="line">  onDownloadProgress: function (progressEvent) &#123;</span><br><span class="line">    <span class="comment">// 对原生进度事件的处理</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `maxContentLength` 定义允许的响应内容的最大尺寸</span></span><br><span class="line">  maxContentLength: <span class="number">2000</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`)，promise 将被 resolve; 否则，promise 将被 rejecte</span></span><br><span class="line">  validateStatus: function (status) &#123;</span><br><span class="line">    return status &amp;gt;= 200 &amp;amp;&amp;amp; status &amp;lt; 300; <span class="comment">// 默认的</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目</span></span><br><span class="line">  <span class="comment">// 如果设置为0，将不会 follow 任何重定向</span></span><br><span class="line">  maxRedirects: <span class="number">5</span>, <span class="comment">// 默认的</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项：</span></span><br><span class="line">  <span class="comment">// `keepAlive` 默认没有启用</span></span><br><span class="line">  httpAgent: new http.Agent(&#123; keepAlive: <span class="literal">true</span> &#125;),</span><br><span class="line">  httpsAgent: new https.Agent(&#123; keepAlive: <span class="literal">true</span> &#125;),</span><br><span class="line"></span><br><span class="line">  <span class="comment">// &quot;proxy&quot; 定义代理服务器的主机名称和端口</span></span><br><span class="line">  <span class="comment">// `auth` 表示 HTTP 基础验证应当用于连接代理，并提供凭据</span></span><br><span class="line">  <span class="comment">// 这将会设置一个 `Proxy-Authorization` 头，覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。</span></span><br><span class="line">  proxy: &#123;</span><br><span class="line">    host: <span class="string">&quot;127.0.0.1&quot;</span>,</span><br><span class="line">    port: <span class="number">9000</span>,</span><br><span class="line">    auth: : &#123;</span><br><span class="line">      username: <span class="string">&quot;mikeymike&quot;</span>,</span><br><span class="line">      password: <span class="string">&quot;rapunz3l&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `cancelToken` 指定用于取消请求的 cancel token</span></span><br><span class="line">  <span class="comment">// （查看后面的 Cancellation 这节了解更多）</span></span><br><span class="line">  cancelToken: new CancelToken(function (cancel) &#123;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="响应结构"><a href="#响应结构" class="headerlink" title="响应结构"></a>响应结构</h2><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="comment">// `data` 由服务器提供的响应</span></span><br><span class="line">  data: &#123;&#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `status`  HTTP 状态码</span></span><br><span class="line">  status: <span class="number">200</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `statusText` 来自服务器响应的 HTTP 状态信息</span></span><br><span class="line">  statusText: <span class="string">&quot;OK&quot;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `headers` 服务器响应的头</span></span><br><span class="line">  headers: &#123;&#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// `config` 是为请求提供的配置信息</span></span><br><span class="line">  config: &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="配置默认值"><a href="#配置默认值" class="headerlink" title="配置默认值"></a>配置默认值</h2><ul><li>可以指定将被用在各个请求的配置默认值</li></ul><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">axios.defaults.baseURL = <span class="string">&#x27;https://api.example.com&#x27;</span>;</span><br><span class="line">axios.defaults.headers.common[<span class="string">&#x27;Authorization&#x27;</span>] = AUTH_TOKEN;</span><br><span class="line">axios.defaults.headers.post[<span class="string">&#x27;Content-Type&#x27;</span>] = <span class="string">&#x27;application/x-www-form-urlencoded&#x27;</span>;</span><br></pre></td></tr></table></figure><ul><li>配置的优先顺序<ul><li>查找顺序是：在 lib/defaults.js 找到的库的默认值，然后是实例的 defaults 属性，最后是请求的 config 参数。<strong>后者优先于前者</strong>。</li></ul></li></ul><h2 id="拦截器"><a href="#拦截器" class="headerlink" title="拦截器"></a>拦截器</h2><ul><li>在请求或响应被 then 或 catch 处理前拦截它们</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加请求拦截器</span></span><br><span class="line">axios.interceptors.request.use(<span class="function"><span class="keyword">function</span> (<span class="params">config</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 在发送请求之前做些什么</span></span><br><span class="line">    <span class="keyword">return</span> config;</span><br><span class="line">  &#125;, <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 对请求错误做些什么</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error);</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加响应拦截器</span></span><br><span class="line">axios.interceptors.response.use(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 对响应数据做点什么</span></span><br><span class="line">    <span class="keyword">return</span> response;</span><br><span class="line">  &#125;, <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 对响应错误做点什么</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error);</span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">Vue.js 2.0 版本推荐使用 axios 来完成 ajax 请求,本文简要描述axios的用法。</summary>
    
    
    
    <category term="前端框架/工具" scheme="https://nuyoah-xlh.github.io/categories/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6-%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="前端框架/工具" scheme="https://nuyoah-xlh.github.io/tags/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6-%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>【面试题】多线程实现有序执行</title>
    <link href="https://nuyoah-xlh.github.io/2022/04/21/%E3%80%90%E9%9D%A2%E8%AF%95%E9%A2%98%E3%80%91%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%AE%9E%E7%8E%B0%E6%9C%89%E5%BA%8F%E6%89%A7%E8%A1%8C/"/>
    <id>https://nuyoah-xlh.github.io/2022/04/21/%E3%80%90%E9%9D%A2%E8%AF%95%E9%A2%98%E3%80%91%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%AE%9E%E7%8E%B0%E6%9C%89%E5%BA%8F%E6%89%A7%E8%A1%8C/</id>
    <published>2022-04-21T15:15:31.815Z</published>
    <updated>2022-04-21T15:38:08.902Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h1 id="有线程A，B，C，C-要等A和B都执行完了才执行，怎么实现？"><a href="#有线程A，B，C，C-要等A和B都执行完了才执行，怎么实现？" class="headerlink" title="有线程A，B，C，C 要等A和B都执行完了才执行，怎么实现？"></a>有线程A，B，C，C 要等A和B都执行完了才执行，怎么实现？</h1><h2 id="LockSupport-AtomicInteger"><a href="#LockSupport-AtomicInteger" class="headerlink" title="LockSupport + AtomicInteger"></a>LockSupport + AtomicInteger</h2><p>​    先执行线程C，用 park() 挂起线程C，线程A、B各自执行完成时，flag 减1并判断是否为0，若为0则用unpark(c)给线程C颁发许可。</p><ul><li>LockSupport.park() 函数表示挂起当前线程</li><li>LockSupport.unpark(c) 函数表示解除线程c的阻塞状态</li><li>AtomicInteger.decrementAndGet() 函数表示将该变量减一，并返回当前变量值（线程安全的原子类）</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        AtomicInteger flag = <span class="keyword">new</span> AtomicInteger(<span class="number">2</span>);</span><br><span class="line"></span><br><span class="line">        Thread c =  <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程C开启，等待线程A、B执行完成才继续执行&quot;</span>);</span><br><span class="line">            LockSupport.park();</span><br><span class="line">            System.out.println(<span class="string">&quot;线程C开始执行&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">        c.start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程A开始执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程A执行完成&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (flag.decrementAndGet() == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="comment">//唤醒指定线程</span></span><br><span class="line">                LockSupport.unpark(c);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程B开始执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程B执行完成&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (flag.decrementAndGet() == <span class="number">0</span>)&#123;</span><br><span class="line">                LockSupport.unpark(c);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h2 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h2><p>​    CountDownLatch 有一个计数器，countDown() 方法对计数器做减操作，await 方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时.</p><ul><li>latch.countDown() 函数将计数器减一</li><li>latch.await() 函数表示，当计数器为0时才接着往下执行，否则陷入阻塞</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        CountDownLatch  latch = <span class="keyword">new</span> CountDownLatch(<span class="number">2</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程A开始执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>));</span><br><span class="line">                latch.countDown();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程A执行完成&quot;</span>);</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程B开始执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>));</span><br><span class="line">                latch.countDown();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程B执行完成&quot;</span>);</span><br><span class="line"></span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程C开启，等待线程A、B执行完成才继续执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                latch.await();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程C执行完成&quot;</span>);</span><br><span class="line"></span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h2 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h2><p>​    CyclicBarrier 与 CountDownLatch 类似 ，它能阻塞一组线程全部到某个状态再同时执行。 CyclicBarrier 与 CountDownLatch 的关键区别在于，所有的线程必须全部到达位置，才能继续执行。 CountDownLatch 用于等待事件，而 CyclicBarrier 用于等待其他线程，在任意一个线程没有完成之前，所有线程都不能继续执行。</p><ul><li>barrier.await() 函数使当前线程阻塞，直到相应数量的线程都执行到了该函数，才会将所有线程解锁，往下执行</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        CyclicBarrier barrier = <span class="keyword">new</span> CyclicBarrier(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//只有所有线程执行到了 await()，所有线程才会继续往下执行</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程A开始执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">//执行业务</span></span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>));</span><br><span class="line">                System.out.println(<span class="string">&quot;线程A执行完成，等待其它线程一起冲破栅栏&quot;</span>);</span><br><span class="line">                barrier.await();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程A执行完成&quot;</span>);</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程B开始执行&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">//执行业务</span></span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>));</span><br><span class="line">                System.out.println(<span class="string">&quot;线程B执行完成，等待其它线程一起冲破栅栏&quot;</span>);</span><br><span class="line">                barrier.await();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程B执行完成&quot;</span>);</span><br><span class="line"></span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;线程C开启，等待线程AB执行完成一起冲破栅栏&quot;</span>);</span><br><span class="line">                barrier.await();</span><br><span class="line">                <span class="comment">//执行业务</span></span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程C执行完成&quot;</span>);</span><br><span class="line"></span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">【面试题】多线程实现有序执行，如何实现？</summary>
    
    
    
    <category term="面试" scheme="https://nuyoah-xlh.github.io/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
    <category term="面试" scheme="https://nuyoah-xlh.github.io/tags/%E9%9D%A2%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>阿里云OSS体验</title>
    <link href="https://nuyoah-xlh.github.io/2022/02/24/%E9%98%BF%E9%87%8C%E4%BA%91OSS%E4%BD%93%E9%AA%8C/"/>
    <id>https://nuyoah-xlh.github.io/2022/02/24/%E9%98%BF%E9%87%8C%E4%BA%91OSS%E4%BD%93%E9%AA%8C/</id>
    <published>2022-02-24T14:39:44.333Z</published>
    <updated>2022-02-26T02:32:25.688Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="一、阿里云oss简介"><a href="#一、阿里云oss简介" class="headerlink" title="一、阿里云oss简介"></a>一、阿里云oss简介</h2><p>​    用户认证需要上传证件图片、首页轮播也需要上传图片，因此我们要做文件服务，阿里云oss是一个很好的分布式文件服务系统，只需要集成阿里云oss即可。</p><h2 id="二、开通“对象存储OSS”服务"><a href="#二、开通“对象存储OSS”服务" class="headerlink" title="二、开通“对象存储OSS”服务"></a>二、开通“对象存储OSS”服务</h2><ul><li>申请阿里云账号</li><li>实名认证</li><li>开通“对象存储OSS”服务</li><li>进入管理控制台</li></ul><h2 id="三、创建Bucket"><a href="#三、创建Bucket" class="headerlink" title="三、创建Bucket"></a>三、创建Bucket</h2><p>选择：标准存储、公共读、不开通，如下：</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-02-24_22-27-33.jpg" alt="20210121192316851.png"></p><h2 id="四、获取用户acesskeys"><a href="#四、获取用户acesskeys" class="headerlink" title="四、获取用户acesskeys"></a>四、获取用户acesskeys</h2><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-02-24_22-29-06.jpg" alt="20210121192316851.png"></p><h2 id="五、使用SDK文档"><a href="#五、使用SDK文档" class="headerlink" title="五、使用SDK文档"></a>五、使用SDK文档</h2><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-02-24_22-29-36.jpg" alt="20210121192316851.png"></p><h2 id="六、开始"><a href="#六、开始" class="headerlink" title="六、开始"></a>六、开始</h2><h3 id="1、搭建service-oss模块"><a href="#1、搭建service-oss模块" class="headerlink" title="1、搭建service-oss模块"></a>1、搭建service-oss模块</h3><ul><li>修改pom.xml，引入阿里云oss依赖</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">       <span class="comment">&lt;!-- 阿里云oss依赖 --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.aliyun.oss<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>aliyun-sdk-oss<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>joda-time<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>joda-time<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></pre></td></tr></table></figure><h3 id="2、添加配置文件application-properties"><a href="#2、添加配置文件application-properties" class="headerlink" title="2、添加配置文件application.properties"></a>2、添加配置文件application.properties</h3><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><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 服务端口</span></span><br><span class="line"><span class="meta">server.port</span>=<span class="string">8205</span></span><br><span class="line"><span class="comment"># 服务名</span></span><br><span class="line"><span class="meta">spring.application.name</span>=<span class="string">service-oss</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 环境设置：dev、test、prod</span></span><br><span class="line"><span class="meta">spring.profiles.active</span>=<span class="string">dev</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#返回json的全局时间格式</span></span><br><span class="line"><span class="meta">spring.jackson.date-format</span>=<span class="string">yyyy-MM-dd HH:mm:ss</span></span><br><span class="line"><span class="meta">spring.jackson.time-zone</span>=<span class="string">GMT+8</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># nacos服务地址</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.discovery.server-addr</span>=<span class="string">localhost:8848</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 这里填写你的oss相关信息由第四步可获取</span></span><br><span class="line"><span class="meta">aliyun.oss.endpoint</span>=<span class="string">oss-cn-shanghai.aliyuncs.com</span></span><br><span class="line"><span class="meta">aliyun.oss.accessKeyId</span>=<span class="string">LTAI5tQ****6GkzqU5bY</span></span><br><span class="line"><span class="meta">aliyun.oss.secret</span>=<span class="string">eWnDWoIK****GkcbjrXH</span></span><br><span class="line"><span class="meta">aliyun.oss.bucket</span>=<span class="string">yygh-xlh</span></span><br></pre></td></tr></table></figure><h3 id="3、启动类"><a href="#3、启动类" class="headerlink" title="3、启动类"></a>3、启动类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.oss;</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.autoconfigure.jdbc.DataSourceAutoConfiguration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.discovery.EnableDiscoveryClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.ComponentScan;</span><br><span class="line"></span><br><span class="line"><span class="comment">//取消数据源自动配置</span></span><br><span class="line"><span class="meta">@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="meta">@ComponentScan(basePackages = &#123;&quot;com.xlh&quot;&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServiceOssApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(ServiceOssApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4、配置网关"><a href="#4、配置网关" class="headerlink" title="4、配置网关"></a>4、配置网关</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#设置路由id</span></span><br><span class="line"><span class="meta">spring.cloud.gateway.routes[3].id</span>=<span class="string">service-oss</span></span><br><span class="line"><span class="comment">#设置路由的uri</span></span><br><span class="line"><span class="meta">spring.cloud.gateway.routes[3].uri</span>=<span class="string">lb://service-oss</span></span><br><span class="line"><span class="comment">#设置路由断言,代理servicerId为auth-service的/auth/路径</span></span><br><span class="line"><span class="meta">spring.cloud.gateway.routes[3].predicates</span>= <span class="string">Path=/*/oss/**</span></span><br></pre></td></tr></table></figure><h3 id="5、测试（可跳过）"><a href="#5、测试（可跳过）" class="headerlink" title="5、测试（可跳过）"></a>5、测试（可跳过）</h3><ul><li>在官方文档提供了实例代码：</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-02-24_22-34-56.jpg" alt="20210121192316851.png"></p><h3 id="6、创建ConstantOssPropertiesUtils配置类"><a href="#6、创建ConstantOssPropertiesUtils配置类" class="headerlink" title="6、创建ConstantOssPropertiesUtils配置类"></a>6、创建ConstantOssPropertiesUtils配置类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.oss.utils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.InitializingBean;</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.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConstantOssPropertiesUtils</span> <span class="keyword">implements</span> <span class="title">InitializingBean</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;aliyun.oss.endpoint&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String endpoint;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;aliyun.oss.accessKeyId&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String accessKeyId;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;aliyun.oss.secret&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String secret;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;aliyun.oss.bucket&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String bucket;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String EDNPOINT;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String ACCESS_KEY_ID;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String SECRECT;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String BUCKET;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        EDNPOINT=endpoint;</span><br><span class="line">        ACCESS_KEY_ID=accessKeyId;</span><br><span class="line">        SECRECT=secret;</span><br><span class="line">        BUCKET=bucket;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="7、封装service接口"><a href="#7、封装service接口" class="headerlink" title="7、封装service接口"></a>7、封装service接口</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.oss.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.multipart.MultipartFile;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">FileService</span> </span>&#123;</span><br><span class="line">    <span class="function">String <span class="title">upload</span><span class="params">(MultipartFile file)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.oss.service.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.aliyun.oss.OSS;</span><br><span class="line"><span class="keyword">import</span> com.aliyun.oss.OSSClientBuilder;</span><br><span class="line"><span class="keyword">import</span> com.xlh.yygh.oss.service.FileService;</span><br><span class="line"><span class="keyword">import</span> com.xlh.yygh.oss.utils.ConstantOssPropertiesUtils;</span><br><span class="line"><span class="keyword">import</span> org.joda.time.DateTime;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.multipart.MultipartFile;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.util.UUID;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileServiceImpl</span> <span class="keyword">implements</span> <span class="title">FileService</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">upload</span><span class="params">(MultipartFile file)</span> </span>&#123;</span><br><span class="line">        String endpoint = ConstantOssPropertiesUtils.EDNPOINT;</span><br><span class="line">        String accessKeyId = ConstantOssPropertiesUtils.ACCESS_KEY_ID;</span><br><span class="line">        String accessKeySecret = ConstantOssPropertiesUtils.SECRECT;</span><br><span class="line">        String bucketName = ConstantOssPropertiesUtils.BUCKET;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 创建OSSClient实例。</span></span><br><span class="line">            OSS ossClient = <span class="keyword">new</span> OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);</span><br><span class="line">            <span class="comment">// 上传文件流。</span></span><br><span class="line">            InputStream inputStream = file.getInputStream();</span><br><span class="line">            String fileName = file.getOriginalFilename();</span><br><span class="line">            <span class="comment">//生成随机唯一值，使用uuid，添加到文件名称里面</span></span><br><span class="line">            String uuid = UUID.randomUUID().toString().replaceAll(<span class="string">&quot;-&quot;</span>,<span class="string">&quot;&quot;</span>);</span><br><span class="line">            fileName = uuid+fileName;</span><br><span class="line">            <span class="comment">//按照当前日期，创建文件夹，上传到创建文件夹里面</span></span><br><span class="line">            <span class="comment">//  2021/02/02/01.jpg</span></span><br><span class="line">            String timeUrl = <span class="keyword">new</span> DateTime().toString(<span class="string">&quot;yyyy/MM/dd&quot;</span>);</span><br><span class="line">            fileName = timeUrl+<span class="string">&quot;/&quot;</span>+fileName;</span><br><span class="line">            <span class="comment">//调用方法实现上传</span></span><br><span class="line">            ossClient.putObject(bucketName, fileName, inputStream);</span><br><span class="line">            <span class="comment">// 关闭OSSClient。</span></span><br><span class="line">            ossClient.shutdown();</span><br><span class="line">            <span class="comment">//上传之后文件路径</span></span><br><span class="line">            <span class="comment">// https://yygh-xlh.oss-cn-shanghai.aliyuncs.com/01.jpg</span></span><br><span class="line">            String url = <span class="string">&quot;https://&quot;</span>+bucketName+<span class="string">&quot;.&quot;</span>+endpoint+<span class="string">&quot;/&quot;</span>+fileName;</span><br><span class="line">            <span class="comment">//返回</span></span><br><span class="line">            <span class="keyword">return</span> url;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="8、封装controller接口"><a href="#8、封装controller接口" class="headerlink" title="8、封装controller接口"></a>8、封装controller接口</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.oss.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.xlh.yygh.common.result.Result;</span><br><span class="line"><span class="keyword">import</span> com.xlh.yygh.oss.service.FileService;</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.PostMapping;</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.multipart.MultipartFile;</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;/api/oss/file&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileApiController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> FileService fileService;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//上传文件到阿里云oss</span></span><br><span class="line">    <span class="meta">@PostMapping(&quot;/fileUpload&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Result <span class="title">fileUpload</span><span class="params">(MultipartFile file)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//获取上传文件</span></span><br><span class="line">        String url = fileService.upload(file);</span><br><span class="line">        <span class="keyword">return</span> Result.ok(url);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="9、完成"><a href="#9、完成" class="headerlink" title="9、完成"></a>9、完成</h3><p>​    执行上传接口后，就会按照规则上传到指定目录并返回文件的访问地址。</p>]]></content>
    
    
    <summary type="html">阿里云oss是一个很好的分布式文件服务系统。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>MongoDB+SpringBoot整合</title>
    <link href="https://nuyoah-xlh.github.io/2022/02/07/MongoDB+SpringBoot%E6%95%B4%E5%90%88/"/>
    <id>https://nuyoah-xlh.github.io/2022/02/07/MongoDB+SpringBoot%E6%95%B4%E5%90%88/</id>
    <published>2022-02-07T11:25:46.829Z</published>
    <updated>2022-02-26T02:20:40.226Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="MongoDB-简介"><a href="#MongoDB-简介" class="headerlink" title="MongoDB 简介"></a>MongoDB 简介</h2><ul><li>MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。</li><li>MongoDB 将数据存储为一个文档，数据结构由键值(key=&gt;value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档，数组及文档数组。</li></ul><h3 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h3><ul><li>网站数据：Mongo非常适合实时的插入，更新与查询，并具备网站实时数据存储所需的复制及高度伸缩性。</li><li>缓存：由于性能很高，Mongo也适合作为信息基础设施的缓存层。在系统重启之后，由Mongo搭建的持久化缓存层可以避免下层的数据源过载。</li><li>大尺寸，低价值的数据：使用传统的关系型数据库存储一些数据时可能会比较昂贵， 在此之前，很多时候程序员往往会选择传统的文件进行存储。</li><li>高伸缩性的场景：Mongo非常适合由数十或数百台服务器组成的数据库。Mongo的路线图中已经包含对Map Reduce弓摩的内置支持。</li><li>用于对象及 JSON数据的存储：Mongo的BSON数据格式非常适合文档化格式的存储及查询。</li></ul><h2 id="安装及使用"><a href="#安装及使用" class="headerlink" title="安装及使用"></a>安装及使用</h2><ul><li><p>启动docker</p></li><li><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">[root@localhost ~]<span class="comment"># docker pull mongo:latest</span></span><br></pre></td></tr></table></figure></li><li><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">[root@localhost ~]<span class="comment"># docker run -d --restart=always -p 27017:27017 --name mymongo -v /data/db:/data/db -d mongo</span></span><br></pre></td></tr></table></figure></li><li><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">[root@localhost ~]<span class="comment"># docker exec -it mymongo /bin/bash</span></span><br></pre></td></tr></table></figure></li><li><p>使用MongoDB客户端</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">root@0c7ae9fc2cf4:/<span class="comment"># mongo</span></span><br></pre></td></tr></table></figure></li><li><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">&gt; show dbs</span><br></pre></td></tr></table></figure></li><li><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">&gt; use yygh_hosp</span><br></pre></td></tr></table></figure></li><li><p>获取当前数据库名</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt; db.getName()</span><br></pre></td></tr></table></figure></li><li><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">&gt; db.dropDatabase()</span><br></pre></td></tr></table></figure></li><li><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">&gt; db.createCollection( <span class="string">&quot;test01&quot;</span>)</span><br></pre></td></tr></table></figure></li><li><p>INSERT</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">&gt; db.User.save(&#123;name:<span class="string">&#x27;zhangsan&#x27;</span>,age:21,sex:<span class="literal">true</span>&#125;)        <span class="comment">#往本数据库中的User集合中添加数据</span></span><br><span class="line">&gt; db.User.find()                                <span class="comment">#查看集合</span></span><br></pre></td></tr></table></figure></li><li><p>Query</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">db.User.find(&#123;name:<span class="string">&quot;zhangsan&quot;</span>&#125;)    <span class="comment">#效果类似 select * from User where name = &#x27;zhangsan&#x27;</span></span><br><span class="line">db.User.find(&#123;age:21&#125;, &#123;<span class="string">&#x27;name&#x27;</span>:1, <span class="string">&#x27;age&#x27;</span>:1&#125;)    <span class="comment">#效果类似 select name, age from User where age = 21</span></span><br><span class="line">db.User.update(&#123;name:<span class="string">&quot;zhangsan&quot;</span>&#125;, &#123;<span class="variable">$set</span>:&#123;age:100, sex:0&#125;&#125;)<span class="comment"># update Userset age = 100, sex = 0 where name = </span></span><br><span class="line"><span class="comment">#  &#x27;user1&#x27;</span></span><br><span class="line">db.User.remove(id)   <span class="comment"># 移除对应id的行</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="Spring-boot集成mongodb"><a href="#Spring-boot集成mongodb" class="headerlink" title="Spring boot集成mongodb"></a>Spring boot集成mongodb</h2><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>​    spring-data-mongodb提供了MongoTemplate与MongoRepository两种方式访问mongodb，MongoRepository操作简单，MongoTemplate操作灵活，我们在项目中可以灵活适用这两种方式操作mongodb，MongoRepository的缺点是不够灵活，MongoTemplate正好可以弥补不足。</p><h3 id="基于MongoTemplate"><a href="#基于MongoTemplate" class="headerlink" title="基于MongoTemplate"></a>基于MongoTemplate</h3><p>​    使用 Spring Initializr 快速初始化一个 Spring Boot 工程</p><ul><li><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-mongodb<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-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>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">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>joda-time<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>joda-time<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.10.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  </span><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">exclusions</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                   <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.junit.vintage<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>junit-vintage-engine<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;/<span class="name">exclusions</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></pre></td></tr></table></figure></li><li><p>配置<code>application.properties</code></p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">spring.data.mongodb.uri</span>=<span class="string">mongodb://192.168.243.130:27017/test</span></span><br></pre></td></tr></table></figure></li><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mongo.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.data.annotation.Id;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.mapping.Document;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="comment">//对应mongodb中的User集合</span></span><br><span class="line"><span class="meta">@Document(&quot;User&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Id</span></span><br><span class="line">    <span class="keyword">private</span> String id;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> String email;</span><br><span class="line">    <span class="keyword">private</span> String createDate;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>测试</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mongo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.xlh.mongo.bean.User;</span><br><span class="line"><span class="keyword">import</span> lombok.val;</span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.Test;</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.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.MongoTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.query.Criteria;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.query.Query;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.jws.soap.SOAPBinding;</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">@SpringBootTest</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MongoApplicationTests</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//注入MongoTemplate</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> MongoTemplate mongoTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//添加数据</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        User user=<span class="keyword">new</span> User();</span><br><span class="line">        user.setAge(<span class="number">22</span>);</span><br><span class="line">        user.setEmail(<span class="string">&quot;1583677918@qq.com&quot;</span>);</span><br><span class="line">        user.setName(<span class="string">&quot;xlh&quot;</span>);</span><br><span class="line">        User user1 = mongoTemplate.insert(user);</span><br><span class="line">        System.out.println(user1);</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="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findAll</span><span class="params">()</span></span>&#123;</span><br><span class="line">        List&lt;User&gt; all = mongoTemplate.findAll(User.class);</span><br><span class="line">        System.out.println(all);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//根据id查询</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findById</span><span class="params">()</span></span>&#123;</span><br><span class="line">        User user=mongoTemplate.findById(<span class="string">&quot;6202353e4d924e22771a5cdb&quot;</span>,User.class);</span><br><span class="line">        System.out.println(user);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//条件查询</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findQuery</span><span class="params">()</span></span>&#123;</span><br><span class="line">        Query query=<span class="keyword">new</span> Query(Criteria.where(<span class="string">&quot;name&quot;</span>).is(<span class="string">&quot;xlh&quot;</span>).and(<span class="string">&quot;age&quot;</span>).is(<span class="number">22</span>));</span><br><span class="line">        List&lt;User&gt; users = mongoTemplate.find(query, User.class);</span><br><span class="line">        System.out.println(users);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="基于MongoRepository"><a href="#基于MongoRepository" class="headerlink" title="基于MongoRepository"></a>基于MongoRepository</h3><ul><li><p>定义一个接口继承自MongoRepository</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mongo.repository;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.xlh.mongo.bean.User;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.repository.MongoRepository;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">UserRepository</span> <span class="keyword">extends</span> <span class="title">MongoRepository</span>&lt;<span class="title">User</span>,<span class="title">String</span>&gt; </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>测试</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mongo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.xlh.mongo.bean.User;</span><br><span class="line"><span class="keyword">import</span> com.xlh.mongo.repository.UserRepository;</span><br><span class="line"><span class="keyword">import</span> lombok.val;</span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.Test;</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.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.domain.*;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.MongoTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.query.Criteria;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.mongodb.core.query.Query;</span><br><span class="line"></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">@SpringBootTest</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MongoApplicationTests01</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//注入MongoTemplate</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserRepository userRepository;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//添加数据</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        User user=<span class="keyword">new</span> User();</span><br><span class="line">        user.setAge(<span class="number">20</span>);</span><br><span class="line">        user.setEmail(<span class="string">&quot;1583677918@qq.com&quot;</span>);</span><br><span class="line">        user.setName(<span class="string">&quot;xlh2&quot;</span>);</span><br><span class="line">        User user1 = userRepository.save(user);</span><br><span class="line">        System.out.println(user1);</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="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findAll</span><span class="params">()</span></span>&#123;</span><br><span class="line">        List&lt;User&gt; all = userRepository.findAll();</span><br><span class="line">        System.out.println(all);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//根据id查询</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findById</span><span class="params">()</span></span>&#123;</span><br><span class="line">        User user=userRepository.findById(<span class="string">&quot;6202353e4d924e22771a5cdb&quot;</span>).get();</span><br><span class="line">        System.out.println(user);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//条件查询</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findQuery</span><span class="params">()</span></span>&#123;</span><br><span class="line">        User user=<span class="keyword">new</span> User();</span><br><span class="line">        user.setName(<span class="string">&quot;xlh2&quot;</span>);</span><br><span class="line">        Example&lt;User&gt; example=Example.of(user);</span><br><span class="line">        List&lt;User&gt; users = userRepository.findAll(example);</span><br><span class="line">        System.out.println(users);</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="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findLike</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//设置模糊查询规则</span></span><br><span class="line">        ExampleMatcher matcher=ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING).withIgnoreCase(<span class="keyword">true</span>);</span><br><span class="line">        User user=<span class="keyword">new</span> User();</span><br><span class="line">        user.setName(<span class="string">&quot;xl&quot;</span>);</span><br><span class="line">        Example&lt;User&gt; example=Example.of(user,matcher);</span><br><span class="line">        List&lt;User&gt; all=userRepository.findAll(example);</span><br><span class="line">        System.out.println(all);</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="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findPage</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//设置分页参数</span></span><br><span class="line">        <span class="comment">//0为第一页</span></span><br><span class="line">        Pageable pageable = PageRequest.of(<span class="number">0</span>, <span class="number">3</span>);</span><br><span class="line">        User user=<span class="keyword">new</span> User();</span><br><span class="line">        user.setName(<span class="string">&quot;xlh2&quot;</span>);</span><br><span class="line">        Example&lt;User&gt; example=Example.of(user);</span><br><span class="line">        Page&lt;User&gt; page = userRepository.findAll(example,pageable);</span><br><span class="line">        System.out.println(page);</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="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">update</span><span class="params">()</span></span>&#123;</span><br><span class="line">        User user=userRepository.findById(<span class="string">&quot;6202353e4d924e22771a5cdb&quot;</span>).get();</span><br><span class="line">        user.setName(<span class="string">&quot;001&quot;</span>);</span><br><span class="line">        user.setEmail(<span class="string">&quot;111@qq.com&quot;</span>);</span><br><span class="line">        User user1=userRepository.save(user);</span><br><span class="line">        System.out.println(user1);</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="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">delete</span><span class="params">()</span></span>&#123;</span><br><span class="line">        userRepository.deleteById(<span class="string">&quot;6202353e4d924e22771a5cdb&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></li></ul>]]></content>
    
    
    <summary type="html">本文是学习MongoDB+SpringBoot整合的相关笔记。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>Docker入门笔记</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/24/Docker%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/24/Docker%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/</id>
    <published>2022-01-24T05:42:43.844Z</published>
    <updated>2022-10-07T06:16:07.119Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="Docker简介"><a href="#Docker简介" class="headerlink" title="Docker简介"></a>Docker简介</h2><ul><li>Docker之所以发展如此迅速，也是因为它对此给出了一个标准化的解决方案—–系统平滑移植，容器虚拟化技术。</li><li>环境配置相当麻烦，换一台机器，就要重来一次，费力费时。很多人想到，能不能从根本上解决问题，软件可以带环境安装？也就是说，安装的时候，把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。</li><li>Docker的出现使得其得以打破过去「程序即应用」的观念。透过镜像将作业系统核心除外，运作应用程式所需要的系统环境，由下而上打包，达到应用程式跨平台间的无缝接轨运作。</li><li>Docker是基于Go语言实现的云开源项目。</li><li>Linux容器技术的出现就解决了这样一个问题，而 Docker 就是在它的基础上发展过来的。将应用打成镜像，通过镜像成为运行在Docker容器上面的实例，而 Docker容器在任何操作系统上都是一致的，这就实现了跨平台、跨服务器。只需要一次配置好环境，换到别的机子上就可以一键部署好，大大简化了操作。</li><li><strong>总结就是，Docker解决了运行环境和配置问题的软件容器， 方便做持续集成并有助于整体发布的容器虚拟化技术。</strong></li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-24_13-56-24.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-24_13-58-42.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><h3 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h3><ul><li>Docker支持以下的CentOS版本:<ul><li>Docker运行在CentOS7上，要求系统为64位、系统内核版本为3.8以上。</li><li>Docker运行在CentOS-6.5或更高的版本的CentOS上，要求系统为64位、系统内核版本为2.6.32-431或者更高版本。</li></ul></li></ul><h3 id="三要素"><a href="#三要素" class="headerlink" title="三要素"></a>三要素</h3><ul><li><strong>镜像</strong><ul><li>Docker 镜像（Image）就是一个只读的模板。镜像可以用来创建 Docker 容器，一个镜像可以创建很多容器。</li><li>docker镜像文件类似于Java的类模板，而docker容器实例类似于java中new出来的实例对象。</li></ul></li><li><strong>容器</strong><ul><li>容器是用镜像创建的运行实例</li><li>容器为镜像提供了一个标准的和隔离的运行环境，它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台</li><li>可以把容器看做是一个简易版的 Linux 环境</li></ul></li><li><strong>仓库</strong><ul><li>仓库是集中存放镜像文件的场所。</li><li>仓库分为公开仓库和私有仓库两种形式。最大的公开仓库是 Docker Hub(<a href="https://hub.docker.com/)%EF%BC%8C">https://hub.docker.com/)，</a></li></ul></li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-24_14-20-48.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p><h3 id="开始安装"><a href="#开始安装" class="headerlink" title="开始安装"></a>开始安装</h3><ul><li><p>官方文档：<a href="http://·https//docs.docker.com/engine/install/centos/">http://xn--https-pja//docs.docker.com/engine/install/centos/</a></p></li><li><p>虚拟机联网</p></li><li><p>安装gcc</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">[root@hadoop1 ~]<span class="comment"># yum -y install gcc</span></span><br></pre></td></tr></table></figure></li><li><p>安装gcc-c++</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">[root@hadoop1 ~]<span class="comment"># yum -y install gcc-c++</span></span><br></pre></td></tr></table></figure></li><li><p>安装yum-utils</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">[root@hadoop1 ~]<span class="comment"># yum install -y yum-utils</span></span><br></pre></td></tr></table></figure></li><li><p>设置stable镜像仓库(这里使用阿里云镜像)</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">[root@hadoop1 ~]<span class="comment"># yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span></span><br></pre></td></tr></table></figure></li><li><p>安装docker</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">[root@localhost etc]<span class="comment"># yum -y install docker-ce docker-ce-cli containerd.io</span></span><br></pre></td></tr></table></figure></li><li><p>启动docker</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">[root@localhost /]<span class="comment"># systemctl start docker</span></span><br></pre></td></tr></table></figure></li><li><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">[root@localhost /]<span class="comment"># docker version</span></span><br></pre></td></tr></table></figure></li><li><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">[root@localhost /]<span class="comment"># docker run hello-world</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="镜像加速"><a href="#镜像加速" class="headerlink" title="镜像加速"></a>镜像加速</h2><ul><li><p>注册/登录阿里云账户：<a href="https://promotion.aliyun.com/ntms/act/kubernetes.html">https://promotion.aliyun.com/ntms/act/kubernetes.html</a></p></li><li><p>首页-&gt;控制台-&gt;容器镜像服务，并复制加速地址，根据下方版本提示复制命令运行进行配置即可</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-24_19-49-40.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p></li><li><p>运行</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-25_13-23-35.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p></li><li><p>对比</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-25_13-26-13.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p></li></ul><h2 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h2><h3 id="基础命令"><a href="#基础命令" class="headerlink" title="基础命令"></a>基础命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">启动docker： systemctl start docker</span><br><span class="line">停止docker： systemctl stop docker</span><br><span class="line">重启docker： systemctl restart docker</span><br><span class="line">查看docker状态： systemctl status docker</span><br><span class="line">开机启动： systemctl <span class="built_in">enable</span> docker</span><br><span class="line">查看docker概要信息： docker info</span><br><span class="line">查看docker总体帮助文档： docker --<span class="built_in">help</span></span><br><span class="line">查看docker命令帮助文档： docker 具体命令 --<span class="built_in">help</span></span><br></pre></td></tr></table></figure><h3 id="镜像命令"><a href="#镜像命令" class="headerlink" title="镜像命令"></a>镜像命令</h3><ul><li><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">docker images</span><br></pre></td></tr></table></figure><ul><li><p>显示的表中名称意义</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">REPOSITORY：表示镜像的仓库源</span><br><span class="line">TAG：镜像的标签版本号</span><br><span class="line">IMAGE ID：镜像ID</span><br><span class="line">CREATED：镜像创建时间</span><br><span class="line">SIZE：镜像大小</span><br></pre></td></tr></table></figure></li><li><p>OPTIONS说明：</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">-a :列出本地所有的镜像（含历史映像层）</span><br><span class="line">-q :只显示镜像ID。</span><br></pre></td></tr></table></figure></li></ul></li><li><p>去总库查询相关镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">docker search [OPTIONS] 镜像名字 某个镜像名字</span><br><span class="line">OPTIONS说明：</span><br><span class="line">--<span class="built_in">limit</span> : 只列出N个镜像，默认25个</span><br><span class="line">例子：</span><br><span class="line">docker search --<span class="built_in">limit</span> 5 redis</span><br></pre></td></tr></table></figure></li><li><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">docker pull 镜像名字[:TAG]</span><br></pre></td></tr></table></figure><ul><li>说明：tag为版本号，默认为最新版</li></ul></li><li><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">docker system df   <span class="comment">#查看镜像/容器/数据卷所占的空间</span></span><br></pre></td></tr></table></figure></li><li><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">docker rmi  -f 镜像ID/名字:tag</span><br></pre></td></tr></table></figure></li></ul><h3 id="docker虚悬镜像"><a href="#docker虚悬镜像" class="headerlink" title="docker虚悬镜像"></a>docker虚悬镜像</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">仓库名、标签都是&lt;none&gt;的镜像，俗称虚悬镜像</span><br></pre></td></tr></table></figure><h3 id="容器命令"><a href="#容器命令" class="headerlink" title="容器命令"></a>容器命令</h3><ul><li><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">[root@localhost ~]<span class="comment"># docker pull ubuntu</span></span><br></pre></td></tr></table></figure></li><li><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">docker run [OPTIONS] 镜像名 [COMMAND] [ARG...]</span><br></pre></td></tr></table></figure><ul><li><p>OPTIONS说明:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">--name=<span class="string">&quot;容器新名字&quot;</span>       <span class="comment">#为容器指定一个名称</span></span><br><span class="line">-d                      <span class="comment">#后台运行容器并返回容器ID，也即启动守护式容器(后台运行)</span></span><br><span class="line">-i                      <span class="comment">#以交互模式运行容器，通常与 -t 同时使用</span></span><br><span class="line">-t                    <span class="comment">#为容器重新分配一个伪输入终端，通常与 -i 同时使用；也即启动交互式容器(前台有伪终端，等待交互)</span></span><br><span class="line">-P                  <span class="comment">#随机端口映射，大写P</span></span><br><span class="line">-p                    <span class="comment">#指定端口映射，小写p</span></span><br></pre></td></tr></table></figure></li><li><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">[root@localhost ~]<span class="comment"># docker run -it ubuntu /bin/bash</span></span><br></pre></td></tr></table></figure></li></ul></li><li><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">exit</span></span><br></pre></td></tr></table></figure></li><li><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">docker start 容器ID或者容器名</span><br></pre></td></tr></table></figure></li><li><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">docker stop 容器ID或者容器名</span><br></pre></td></tr></table></figure></li><li><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">docker rm 容器ID</span><br></pre></td></tr></table></figure></li><li><p>查看运行中的容器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">docker ps [OPTIONS]</span><br><span class="line">OPTIONS说明：</span><br><span class="line">-a :列出当前所有正在运行的容器+历史上运行过的</span><br><span class="line">-l :显示最近创建的容器。</span><br><span class="line">-n：显示最近n个创建的容器。</span><br><span class="line">-q :静默模式，只显示容器编号。</span><br><span class="line">[root@localhost ~]<span class="comment"># docker ps</span></span><br></pre></td></tr></table></figure></li><li><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">docker cp  容器ID:容器内路径 目的主机路径</span><br></pre></td></tr></table></figure></li><li><p>export 导出容器的内容留作为一个tar归档文件</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">docker <span class="built_in">export</span> 容器ID &gt; 文件名.tar</span><br></pre></td></tr></table></figure></li><li><p>import 从tar包中的内容创建一个新的文件系统再导入为镜像</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">cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号</span><br></pre></td></tr></table></figure></li></ul><h3 id="重要"><a href="#重要" class="headerlink" title="重要"></a>重要</h3><ul><li><p>有镜像才能创建容器，这是根本前提</p></li><li><p>Docker容器后台运行,就必须有一个前台进程，否则会自行销毁</p><ul><li><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">docker run -it redis:6.0.8</span><br></pre></td></tr></table></figure></li><li><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">docker run -d redis:6.0.8</span><br></pre></td></tr></table></figure></li></ul></li><li><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">docker logs 容器ID</span><br></pre></td></tr></table></figure></li><li><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">docker top 容器ID</span><br></pre></td></tr></table></figure></li><li><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">docker <span class="built_in">exec</span>/attach -it 容器ID bashShell</span><br></pre></td></tr></table></figure><ul><li>exec 是在容器中打开新的终端，并且可以启动新的进程 用exit退出，不会导致容器的停止。(推荐)</li><li>attach 直接进入容器启动命令的终端，不会启动新的进程 用exit退出，会导致容器的停止。</li></ul></li></ul><h2 id="镜像"><a href="#镜像" class="headerlink" title="镜像"></a>镜像</h2><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p>​    镜像是一种轻量级、可执行的独立软件包，它包含运行某个软件所需的所有内容，我们把应用程序和配置依赖打包好形成一个可交付的运行环境，这个运行环境就是image镜像文件。</p><h3 id="分层的镜像"><a href="#分层的镜像" class="headerlink" title="分层的镜像"></a>分层的镜像</h3><ul><li><p>UnionFS（联合文件系统）</p><p>​    Union文件系统（UnionFS）是一种分层、轻量级并且高性能的文件系统，它支持<strong>对文件系统的修改作为一次提交</strong>来一层层的叠加，同时可以将不同目录挂载到同一个虚拟文件系统下。</p></li><li><p>UnionFS是 Docker 镜像的基础。镜像可以通过分层来进行继承，基于基础镜像（没有父镜像），可以制作各种具体的应用镜像。</p></li><li><p>特性：一次同时加载多个文件系统，但从外面看起来，只能看到一个文件系统，联合加载会把各层文件系统叠加起来，这样最终的文件系统会包含所有底层的文件和目录</p></li></ul><h3 id="Docker镜像加载原理"><a href="#Docker镜像加载原理" class="headerlink" title="Docker镜像加载原理"></a>Docker镜像加载原理</h3><ul><li>docker的镜像实际上由一层一层的文件系统组成（UnionFS）</li><li>bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统，在Docker镜像的最底层是引导文件系统bootfs。</li><li>rootfs (root file system) ，在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版，比如Ubuntu，Centos等等。 对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。</li><li>镜像分层最大的一个好处就是共享资源，方便复制迁移，就是为了复用。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-26_19-36-15.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p><h3 id="commit"><a href="#commit" class="headerlink" title="commit"></a>commit</h3><ul><li><p>docker commit提交容器副本使之成为一个新的镜像</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">docker commit -m=<span class="string">&quot;提交的描述信息&quot;</span> -a=<span class="string">&quot;作者&quot;</span> 容器ID 要创建的目标镜像名:[标签名]</span><br></pre></td></tr></table></figure></li><li><p>例子</p><ul><li><p>原始的默认Ubuntu镜像是不带着vim命令的</p></li><li><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">apt-get update    <span class="comment">#更新包管理工具</span></span><br><span class="line">apt-get -y install vim    <span class="comment">#安装vim</span></span><br></pre></td></tr></table></figure></li><li><p>安装完成后，commit新镜像</p></li></ul></li><li><p>Docker中的镜像分层，支持通过扩展现有镜像，创建新的镜像。</p></li></ul><h3 id="提交镜像到阿里云库"><a href="#提交镜像到阿里云库" class="headerlink" title="提交镜像到阿里云库"></a>提交镜像到阿里云库</h3><ul><li><p>进入<a href="https://promotion.aliyun.com/ntms/act/kubernetes.html%EF%BC%8C%E8%BF%9B%E5%85%A5%E6%8E%A7%E5%88%B6%E5%8F%B0%E5%B9%B6%E5%88%9B%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%AE%9E%E4%BE%8B">https://promotion.aliyun.com/ntms/act/kubernetes.html，进入控制台并创建个人实例</a></p></li><li><p>创建命名空间</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-27_21-59-56.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p></li><li><p>创建本地仓库</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-27_22-01-44.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p></li><li><p>根据生成的提示，复制命令到Linux中运行</p></li></ul><h3 id="Docker私有库"><a href="#Docker私有库" class="headerlink" title="Docker私有库"></a>Docker私有库</h3><ul><li><p>下载镜像Registry</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">docker pull registry </span><br></pre></td></tr></table></figure></li><li><p>运行私有库Registry，相当于本地有个私有Docker hub</p></li><li><p>修改符合私服规范的Tag</p></li><li><p>修改配置文件使之支持http</p></li><li><p>push推送到私服库</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">docker push ip:port/id:tag</span><br></pre></td></tr></table></figure></li></ul><h2 id="Docker容器数据卷"><a href="#Docker容器数据卷" class="headerlink" title="Docker容器数据卷"></a>Docker容器数据卷</h2><p>​    Docker挂载主机目录访问如果出现cannot open directory .: Permission denied，解决办法：在挂载目录后多加一个<code>--privileged=true</code>参数即可  </p><ul><li><p>卷就是目录或文件，存在于一个或多个容器中，由docker挂载到容器，但不属于联合文件系统，因此能够绕过Union File System提供一些用于持续存储或共享数据的特性：卷的设计目的就是数据的持久化，完全独立于容器的生存周期，因此Docker不会在容器删除时删除其挂载的数据卷</p></li><li><p>将运用与运行的环境打包镜像，run后形成容器实例运行 ，但是我们对数据的要求希望是持久化的</p></li><li><p>将docker容器内的数据保存进宿主机的磁盘中</p></li><li><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">docker run -it --privileged=<span class="literal">true</span> -v /宿主机绝对路径目录:/容器内目录 镜像名</span><br></pre></td></tr></table></figure><ul><li><p>容器和宿主机之间数据共享</p></li><li><p>读写规则映射添加说明</p><ul><li>读写(默认)：rw</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-28_20-12-45.jpg" alt="Snipaste_2021-07-29_17-21-42.jpg"></p><ul><li>只读：ro</li></ul></li></ul></li><li><p>卷的继承和共享</p><ul><li><p>容器1完成和宿主机的映射</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it  --privileged=<span class="literal">true</span> -v /mydocker/u:/tmp --name u1 ubuntu</span><br></pre></td></tr></table></figure></li><li><p>容器2继承容器1的卷规则</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it  --privileged=<span class="literal">true</span> --volumes-from 父类  --name u2 ubuntu</span><br></pre></td></tr></table></figure></li></ul></li></ul><h2 id="常用镜像安装"><a href="#常用镜像安装" class="headerlink" title="常用镜像安装"></a>常用镜像安装</h2><h3 id="tomcat"><a href="#tomcat" class="headerlink" title="tomcat"></a>tomcat</h3><ul><li><p><a href="https://hub.docker.com/">dockerhub</a>上面查找tomcat镜像</p></li><li><p>也可通过<code>docker search tomcat</code>搜索相关镜像</p></li><li><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">docker pull tomcat</span><br></pre></td></tr></table></figure></li><li><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">[root@localhost ~]<span class="comment"># docker run -d -p 8080:8080 --name t1 tomcat</span></span><br></pre></td></tr></table></figure><ul><li>注：新版tomcat可能会出现访问首页404的问题（没有映射端口或者没有关闭防火墙），解决方案：<ul><li>先成功启动tomcat</li><li>进入命令行窗口<code>[root@localhost ~]# docker exec -it 1e843aca6059 bash</code></li><li>查看目录<code>ls -l</code>,发现有<code>webapps</code>和<code>webapps.dist</code>两个文件夹，需要将<code>webapps</code>删除，将<code>webapps.dist</code>命名为<code>webapps</code></li><li>删除<code>webapps</code>：<code>rm -r webapps</code></li><li>重命名：<code>mv webapps.dist webapps</code></li><li>此时即可访问<code>localhost:8080</code>端口</li></ul></li></ul></li><li><p>可安装免修改的tomcat8</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">docker pull billygoo/tomcat8-jdk8</span><br><span class="line">docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8</span><br></pre></td></tr></table></figure></li></ul><h3 id="mysql"><a href="#mysql" class="headerlink" title="mysql"></a>mysql</h3><ul><li>docker安装完MySQL并run出容器后，建议请先修改完字符集编码后再新建mysql库-表-插数据</li></ul><h3 id="redis"><a href="#redis" class="headerlink" title="redis"></a>redis</h3><ul><li><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">docker pull redis:6.0.8</span><br></pre></td></tr></table></figure></li><li><p>在宿主机下新建目录<code>/app/redis</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">mkdir -p /app/redis</span><br></pre></td></tr></table></figure></li><li><p>将一个redis.conf文件模板拷贝进/app/redis目录下</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">cp /etc/redis.conf /app/redis/</span><br></pre></td></tr></table></figure></li><li><p>修改redis.conf</p><ul><li>允许redis外地连接  必须注释掉 <code>bind 127.0.0.1</code></li><li>将<code>daemonize yes</code>注释起来或者 <code>daemonize no</code>设置，因为该配置和docker run中-d参数冲突，会导致容器一直启动失败</li><li>开启redis数据持久化  appendonly yes  可选</li></ul></li><li><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">docker run  -p 6379:6379 --name myr3 --privileged=<span class="literal">true</span> -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf</span><br></pre></td></tr></table></figure></li><li><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">docker <span class="built_in">exec</span> -it 711a23222ef4 redis-cli</span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    
    <summary type="html">本文简要介绍Docker入门使用和相关操作。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>Nginx反向代理初步使用</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/23/Nginx%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E5%88%9D%E6%AD%A5%E4%BD%BF%E7%94%A8/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/23/Nginx%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E5%88%9D%E6%AD%A5%E4%BD%BF%E7%94%A8/</id>
    <published>2022-01-23T12:44:23.107Z</published>
    <updated>2022-02-26T02:31:42.320Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>​    客户端对代理是无感知的，因为客户端不需要任何配置就可以访问，我们只需要将请求发送到反向代理服务器，由反向代理服务器去选择目标服务器获取数据后，在返回给客户端，此时反向代理服务器和目标服务器对外就是一个服务器，暴露的是代理服务器地址，隐藏了真实服务器IP地址。</p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><ul><li><p>下载安装Nginx（这里以window版为例）</p></li><li><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></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">     listen       9001;</span><br><span class="line">     server_name  localhost;</span><br><span class="line"></span><br><span class="line">location ~ /hosp/ &#123;           </span><br><span class="line">    proxy_pass http://localhost:8201;</span><br><span class="line">&#125;</span><br><span class="line">location ~ /cmn/ &#123;           </span><br><span class="line">    proxy_pass http://localhost:8202;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>9001为客户访问端口，当路径中使用正则表达式匹配到<code>hosp</code>时，使用<code>http://localhost:8201</code>作为请求地址，如果匹配到<code>cmn</code>，则使用<code>http://localhost:8202</code>作为请求地址。</li></ul></li></ul>]]></content>
    
    
    <summary type="html">后端有很多服务模块，每个模块都有对应的访问路径与端口，为了提供统一的api接口，使用nginx作为反向代理服务器是有效的，</summary>
    
    
    
    <category term="前端框架/工具" scheme="https://nuyoah-xlh.github.io/categories/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6-%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="前端框架/工具" scheme="https://nuyoah-xlh.github.io/tags/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6-%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>Redis6实用笔记</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/19/Redis6%E5%AE%9E%E7%94%A8%E7%AC%94%E8%AE%B0/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/19/Redis6%E5%AE%9E%E7%94%A8%E7%AC%94%E8%AE%B0/</id>
    <published>2022-01-19T09:09:38.749Z</published>
    <updated>2022-02-26T02:30:51.593Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="NoSQL数据库简介"><a href="#NoSQL数据库简介" class="headerlink" title="NoSQL数据库简介"></a>NoSQL数据库简介</h2><h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>​    随着Web2.0的时代的到来，用户访问量大幅度提升，同时产生了大量的用户数据。加上后来的智能移动设备的普及，所有的互联网平台都面临了巨大的性能挑战。</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-19_17-16-48.jpg" alt="20201019172422525.jpg"></p><h3 id="解决CPU及内存压力"><a href="#解决CPU及内存压力" class="headerlink" title="解决CPU及内存压力"></a>解决CPU及内存压力</h3><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-19_17-18-29.jpg" alt="20201019172422525.jpg"></p><h3 id="解决IO压力"><a href="#解决IO压力" class="headerlink" title="解决IO压力"></a>解决IO压力</h3><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-19_17-19-01.jpg" alt="20201019172422525.jpg"></p><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>​    NoSQL(NoSQL = Not Only SQL )，意即“不仅仅是SQL”，泛指非关系型的数据库。 NoSQL 不依赖业务逻辑方式存储，而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。常用于：</p><ul><li>对数据高并发的读写；</li><li>海量数据的读写；</li><li>对数据高可扩展性的；</li></ul><h3 id="典型的NoSQL数据库"><a href="#典型的NoSQL数据库" class="headerlink" title="典型的NoSQL数据库"></a>典型的NoSQL数据库</h3><ul><li>Memcache</li><li>Redis</li><li>MongoDB</li></ul><h2 id="Redis简介"><a href="#Redis简介" class="headerlink" title="Redis简介"></a>Redis简介</h2><ul><li>Redis是一个开源的key-value存储系统，它支持存储的类型相对较多，包括string(字符串)、list(链表)、set(集合)、set(sorted set –有序集合)和hash（哈希类型）</li><li>Redis支持各种不同方式的排序，数据都是缓存在内存</li><li>Redis会周期性的把更新的数据写入磁盘或者把修改操作写入记录文件中</li><li>实现了master-slave(主从)同步</li><li>应用场景：<ul><li>配合关系型数据库做高速缓存<ul><li>分布式架构，做session共享</li></ul></li><li>存储持久化数据<ul><li>排行榜</li><li>时效性数据</li><li>计数器、秒杀</li></ul></li></ul></li></ul><h2 id="Redis安装"><a href="#Redis安装" class="headerlink" title="Redis安装"></a>Redis安装</h2><p><strong>官网下载：</strong><a href="https://redis.io/%EF%BC%88%E4%B8%80%E8%88%AC%E4%B8%BALinux%E7%89%88%E6%9C%AC%EF%BC%8C%E9%9C%80%E8%A6%81%E5%AE%89%E8%A3%85%E5%88%B0Linux%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%B8%8B%EF%BC%89">https://redis.io/（一般为Linux版本，需要安装到Linux虚拟机下）</a></p><ul><li><p>打开Linux虚拟机，连接网络，在windows下使用<code>xftp</code>将下载的压缩文件传输到Linux的<code>/opt</code>目录下</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-19_17-49-35.jpg" alt="20201019172422525.jpg"></p></li><li><p>在Linux下安装<code>gcc</code>环境(如果为Centos6等低版本Linux，则无法直接使用yum，可自行搜索解决方案)</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">yum install gcc</span><br></pre></td></tr></table></figure></li><li><p>检验gcc环境</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">gcc --version</span><br></pre></td></tr></table></figure></li><li><p>解压redis压缩文件</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">[root@hadoop1 opt]<span class="comment"># tar -zxvf redis-6.2.6.tar.gz </span></span><br></pre></td></tr></table></figure></li><li><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">[root@hadoop1 opt]<span class="comment"># cd redis-6.2.6</span></span><br></pre></td></tr></table></figure></li><li><p>执行<code>make</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">[root@hadoop1 opt]<span class="comment"># make</span></span><br></pre></td></tr></table></figure></li><li><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">[root@hadoop1 redis-6.2.6]<span class="comment"># make install</span></span><br></pre></td></tr></table></figure></li><li><p>安装完成可查看安装目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@hadoop1 redis-6.2.6]<span class="comment"># cd /usr/local/bin</span></span><br><span class="line">[root@hadoop1 bin]<span class="comment"># ls</span></span><br><span class="line">redis-benchmark  redis-check-rdb  redis-sentinel</span><br><span class="line">redis-check-aof  redis-cli        redis-server</span><br></pre></td></tr></table></figure><ul><li>其中：<ul><li>redis-server：Redis服务器启动命令</li><li>redis-cli：客户端，操作入口</li></ul></li></ul></li></ul><h2 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h2><h3 id="前台启动"><a href="#前台启动" class="headerlink" title="前台启动"></a>前台启动</h3><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">[root@hadoop1 bin]<span class="comment"># redis-server</span></span><br></pre></td></tr></table></figure><h3 id="后台启动"><a href="#后台启动" class="headerlink" title="后台启动"></a>后台启动</h3><ul><li><p>拷贝一份<code>redis.conf</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">[root@hadoop1 redis-6.2.6]<span class="comment"># cp redis.conf /etc/redis.conf</span></span><br></pre></td></tr></table></figure></li><li><p>修改启动设置</p><ul><li>到<code>/etc</code>目录下<code>cd /etc</code></li><li>编辑后台配置文件<code>[root@hadoop1 etc]# vi redis.conf</code> </li><li>修改<code>daemonize</code>配置为<code>yes</code>（可通过搜索快速查找）</li></ul></li><li><p>进入安装目录下启动<code>cd /usr/local/bin</code></p></li><li><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">[root@hadoop1 bin]<span class="comment"># redis-server /etc/redis.conf </span></span><br></pre></td></tr></table></figure></li><li><p>访问/测试</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">redis-cli</span><br><span class="line">ping</span><br><span class="line"><span class="built_in">exit</span>    <span class="comment">#退出</span></span><br><span class="line">redis-cli shutdown    <span class="comment">#关闭</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="Redis基本知识"><a href="#Redis基本知识" class="headerlink" title="Redis基本知识"></a>Redis基本知识</h2><ul><li>默认端口：6379</li><li>默认16个数据库，类似数组下标从0开始，初始默认使用0号库</li><li>使用命令 <code>select  #</code> 来切换数据库。如: select 8 </li><li>Redis是单线程+多路IO复用技术</li></ul><h3 id="key键操作"><a href="#key键操作" class="headerlink" title="key键操作"></a>key键操作</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">[root@hadoop1 ~]<span class="comment"># redis-cli</span></span><br><span class="line">127.0.0.1:6379&gt; <span class="built_in">set</span> k1 lucy<span class="comment">#设置键-值</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; <span class="built_in">set</span> k2 marry</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; keys *<span class="comment">#查看所有键</span></span><br><span class="line">1) <span class="string">&quot;k2&quot;</span></span><br><span class="line">2) <span class="string">&quot;k1&quot;</span></span><br><span class="line">127.0.0.1:6379&gt; exists k1<span class="comment">#查看是否存在该键</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379&gt; <span class="built_in">type</span> k1<span class="comment">#查看键的类型</span></span><br><span class="line">string</span><br><span class="line">127.0.0.1:6379&gt; del k1<span class="comment">#删除键</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379&gt; expire k2 10<span class="comment">#设置键的定时时间，-2为已过期，-1为永久</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379&gt; ttl k2<span class="comment">#查看定时状态</span></span><br><span class="line">(<span class="built_in">integer</span>) -2</span><br><span class="line">127.0.0.1:6379&gt; select 1<span class="comment">#选择数据库</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379[1]&gt; dbsize<span class="comment">#查看数据库大小</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br></pre></td></tr></table></figure><h3 id="清除"><a href="#清除" class="headerlink" title="清除"></a>清除</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">flushdb   <span class="comment">#清空当前库</span></span><br><span class="line">flushall   <span class="comment">#通杀全部库</span></span><br></pre></td></tr></table></figure><h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><h3 id="String"><a href="#String" class="headerlink" title="String"></a>String</h3><ul><li><p>String是Redis最基本的类型,是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。</p></li><li><p>一个Redis中字符串value最多可以是512M</p></li><li><p>常用命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><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="built_in">set</span> &lt;key&gt; &lt;value&gt;    <span class="comment">#添加键值对</span></span><br><span class="line">get &lt;key&gt;            <span class="comment">#查询对应键值</span></span><br><span class="line">append &lt;key&gt; &lt;value&gt;    <span class="comment">#将给定的&lt;value&gt; 追加到原值的末尾</span></span><br><span class="line">strlen &lt;key&gt;         <span class="comment">#获得值的长度</span></span><br><span class="line">setnx &lt;key&gt; &lt;value&gt;     <span class="comment">#只有在 key 不存在时    设置 key 的值</span></span><br><span class="line">mget &lt;key1&gt; &lt;key2&gt; &lt;key3&gt;    <span class="comment">#同时设置一个或多个 key-value对  </span></span><br><span class="line">msetnx &lt;key1&gt; &lt;value1&gt; &lt;key2&gt; &lt;value2&gt;     <span class="comment">#同时设置一个或多个 value  </span></span><br><span class="line">getrange &lt;key&gt; &lt;起始位置&gt; &lt;结束位置&gt;    <span class="comment">#获得值的范围，类似java中的substring</span></span><br><span class="line">setrange &lt;key&gt; &lt;起始位置&gt; &lt;value&gt;         <span class="comment">#用 &lt;value&gt;  覆写&lt;key&gt;所储存的字符串值，从&lt;起始位置&gt;开始(索引从0开始)。</span></span><br><span class="line">setex &lt;key&gt; &lt;过期时间&gt; &lt;value&gt;        <span class="comment">#设置键值的同时，设置过期时间，单位秒。</span></span><br></pre></td></tr></table></figure></li><li><p>原子性：指不会被线程调度机制打断</p></li><li><p>内部实际分配的空间一般要高于实际字符串长度。当字符串长度小于1M时，扩容都是加倍现有的空间，如果超过1M，扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。</p></li></ul><h3 id="List"><a href="#List" class="headerlink" title="List"></a>List</h3><p>​    单键多值,Redis 列表是简单的字符串列表，按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部,底层实际是个双向链表.</p><ul><li><p>常用命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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">lpush/rpush &lt;key&gt; &lt;value1&gt; &lt;value2&gt; &lt;value3&gt;   <span class="comment"># 从左边/右边插入一个或多个值</span></span><br><span class="line">lpop/rpop &lt;key&gt;                      <span class="comment">#从左边/右边弹出一个值。值在键在，值光键亡</span></span><br><span class="line">lrange &lt;key&gt; &lt;start&gt; &lt;stop&gt;           <span class="comment">#按照索引下标获得元素(从左到右)</span></span><br><span class="line">lindex &lt;key&gt; &lt;index&gt;                <span class="comment">#按照索引下标获得元素(从左到右)</span></span><br><span class="line">llen &lt;key&gt;                            <span class="comment">#获得列表长度</span></span><br><span class="line">lrem &lt;key&gt; &lt;n&gt; &lt;value&gt;              <span class="comment">#从左边删除n个value(从左到右)</span></span><br><span class="line">lset &lt;key&gt; &lt;index&gt; &lt;value&gt;           <span class="comment">#将列表key下标为index的值替换成value</span></span><br></pre></td></tr></table></figure></li><li><p>连续存储和分散存储结合</p></li></ul><h3 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h3><ul><li><p>不存在重复数据</p></li><li><p>常用命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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">sadd &lt;key&gt; &lt;value1&gt; &lt;value2&gt;     <span class="comment">#将一个或多个元素加入到集合 key 中，已经存在的元素将被忽略</span></span><br><span class="line">smembers &lt;key&gt;                  <span class="comment">#取出该集合的所有值</span></span><br><span class="line">sismember &lt;key&gt; &lt;value&gt;         <span class="comment">#判断集合&lt;key&gt;是否为含有该&lt;value&gt;值，有则为1，没有则为0</span></span><br><span class="line">scard &lt;key&gt;                     <span class="comment">#返回该集合的元素个数</span></span><br><span class="line">srem &lt;key&gt; &lt;value1&gt; &lt;value2&gt;     <span class="comment">#删除集合的一些元素</span></span><br><span class="line">sinter &lt;key1&gt; &lt;key2&gt;    <span class="comment">#返回两个集合的交集元素</span></span><br><span class="line">sunion &lt;key1&gt; &lt;key2&gt;<span class="comment">#返回两个集合的并集元素</span></span><br><span class="line">sdiff &lt;key1&gt; &lt;key2&gt;<span class="comment">#返回两个集合的差集元素(key1中的，却不在key2中的)</span></span><br></pre></td></tr></table></figure></li><li><p>基于哈希表实现，但其value指向同一个对象</p></li></ul><h3 id="Hash"><a href="#Hash" class="headerlink" title="Hash"></a>Hash</h3><ul><li><p>Hash是一个String类型的field和value的映射表，hash特别适合用于存储对象。类似Java里面的Map&lt;String,Object&gt;.</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-20_19-57-23.jpg" alt="20201019172422525.jpg"></p></li><li><p>常用命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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">hset &lt;key&gt; &lt;field&gt; &lt;value&gt;         <span class="comment">#给&lt;key&gt;集合中的&lt;field&gt;键赋值&lt;value&gt;</span></span><br><span class="line">hget &lt;key1&gt; &lt;field&gt;                <span class="comment">#从&lt;key1&gt;集合&lt;field&gt;取出value</span></span><br><span class="line">hmset &lt;key1&gt; &lt;field1&gt; &lt;value1&gt; &lt;field2&gt; &lt;value2&gt; ...    <span class="comment">#批量设置hash的值</span></span><br><span class="line">hexists &lt;key1&gt; &lt;field&gt;               <span class="comment">#查看哈希表 key 中，给定域 field 是否存在。</span></span><br><span class="line">hkeys &lt;key&gt;                          <span class="comment">#列出该hash集合的所有field</span></span><br><span class="line">hvals &lt;key&gt;                          <span class="comment">#列出该hash集合的所有value</span></span><br><span class="line">hsetnx &lt;key&gt; &lt;field&gt; &lt;value&gt;          <span class="comment">#将哈希表key中的域field的值设置为value，当且仅当域field不存在</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="Zset"><a href="#Zset" class="headerlink" title="Zset"></a>Zset</h3><ul><li><p>和Set的不同之处是有序集合Zset的每个成员都关联了一个评分,这个评分被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的，但是评分可以是重复了的。</p></li><li><p>常用命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">zadd &lt;key&gt; &lt;score1&gt; &lt;value1&gt; &lt;score2&gt; &lt;value2&gt;   <span class="comment">#将一个或多个 member 元素及其 score 值加入到有序集 key 当中</span></span><br><span class="line"><span class="comment">#返回有序集 key 中，下标在&lt;start&gt;&lt;stop&gt;之间的元素带WITHSCORES，可以让分数一起和值返回到结果集。 </span></span><br><span class="line">zrange &lt;key&gt; &lt;start&gt; &lt;stop&gt; [WITHSCORES]</span><br><span class="line">zrangebyscore key min max  <span class="comment">#返回有序集key中，所有score值介于min和max之间的成员。有序集成员按 score 值递增(从小到大)次序排列。</span></span><br></pre></td></tr></table></figure></li><li><p>基于哈希和跳跃表</p></li></ul><h3 id="Bitmaps"><a href="#Bitmaps" class="headerlink" title="Bitmaps"></a>Bitmaps</h3><ul><li><p>可以把Bitmaps想象成一个以位为单位的数组， 数组的每个单元只能存储0和1， 数组的下标在Bitmaps中叫做偏移量；</p></li><li><p>常用命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">setbit &lt;key&gt; &lt;offset&gt; &lt;value&gt;     <span class="comment">#设置Bitmaps中某个偏移量的值（0或1）</span></span><br><span class="line">getbit &lt;key&gt; &lt;offset&gt;             <span class="comment">#获取Bitmaps中某个偏移量的值</span></span><br><span class="line">bitcount &lt;key&gt; [start end]        <span class="comment">#统计字符串从start字节到end字节比特值为1的数量</span></span><br><span class="line">bitop and(or/not/xor) &lt;destkey&gt; [key…]   <span class="comment">#bitop是一个复合操作， 它可以做多个Bitmaps操作并将结果保存在destkey中</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="HyperLogLog"><a href="#HyperLogLog" class="headerlink" title="HyperLogLog"></a>HyperLogLog</h3><ul><li><p>用来做基数统计的算法，HyperLogLog 的优点是，在输入元素的数量或者体积非常非常大时，计算基数所需的空间总是固定的、并且是很小的。</p></li><li><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">pfadd &lt;key&gt; &lt;element&gt; [element ...]   <span class="comment">#添加指定元素到 HyperLogLog 中</span></span><br><span class="line">pfcount &lt;key&gt; [key ...]           <span class="comment">#计算的近似基数</span></span><br><span class="line">pfmerge &lt;destkey&gt; &lt;sourcekey&gt; [sourcekey ...]   <span class="comment">#将一个或多个HLL合并后的结果存储在另一个HLL中 </span></span><br></pre></td></tr></table></figure></li></ul><h3 id="Geospatial"><a href="#Geospatial" class="headerlink" title="Geospatial"></a>Geospatial</h3><ul><li><p>元素的2维坐标，在地图上就是经纬度。redis基于该类型，提供了经纬度设置，查询，范围查询，距离查询，经纬度Hash等常见操作。</p></li><li><p>常用命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">geoadd &lt;key&gt; &lt;longitude&gt; &lt;latitude&gt; &lt;member&gt; [longitude latitude member...]   #添加地理位置（经度，纬度，名称）</span><br><span class="line">geopos &lt;key&gt; &lt;member&gt; [member...]             #获得指定地区的坐标值</span><br><span class="line">geodist &lt;key&gt; &lt;member1&gt; &lt;member2&gt; [m|km|ft|mi]      #获取两个位置之间的直线距离</span><br><span class="line">georadius &lt;key&gt; &lt;longitude&gt; &lt;latitude&gt; radius m|km|ft|mi   #以给定的经纬度为中心，找出某一半径内的元素</span><br></pre></td></tr></table></figure></li></ul><h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><h3 id="单位"><a href="#单位" class="headerlink" title="单位"></a>单位</h3><ul><li>支持bytes，不支持bit</li></ul><h3 id="网络配置"><a href="#网络配置" class="headerlink" title="网络配置"></a>网络配置</h3><ul><li>默认情况bind=127.0.0.1只能接受本机的访问请求，不写的情况下，无限制接受任何ip地址的访问；</li><li>如果开启了protected-mode，那么在没有设定bind ip且没有设密码的情况下，Redis只允许接受本机的响应</li><li>tcp-backlog，backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列。在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。</li><li>timeout：一个空闲的客户端维持多少秒会关闭，0表示关闭该功能。即永不关闭。</li><li>tcp-keepalive：对访问客户端的一种心跳检测，每个n秒检测一次。建议设置成60 </li><li>daemonize：是否为后台进程</li></ul><h3 id="LIMITS限制"><a href="#LIMITS限制" class="headerlink" title="LIMITS限制"></a>LIMITS限制</h3><ul><li>maxclients：设置redis同时可以与多少个客户端进行连接；</li><li>maxmemory：建议必须设置，否则，将内存占满，造成服务器宕机；</li></ul><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><ul><li>pidfile<ul><li>存放pid文件的位置，每个实例会产生一个不同的pid文件</li></ul></li><li>dump.rdb<ul><li>在redis.conf中配置文件名称，默认为dump.rdb</li></ul></li></ul><h2 id="发布与订阅"><a href="#发布与订阅" class="headerlink" title="发布与订阅"></a>发布与订阅</h2><ul><li><p>打开一个客户端订阅channel1</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">SUBSCRIBE channel1</span><br></pre></td></tr></table></figure></li><li><p>打开另一个客户端，给channel1发布消息</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">publish channel1 hello</span><br></pre></td></tr></table></figure></li><li><p>第一个客户端可以看到发送的消息</p></li></ul><h2 id="Jedis"><a href="#Jedis" class="headerlink" title="Jedis"></a>Jedis</h2><h3 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h3><ul><li>需要在redis.conf中注释掉<code>bind 127.0.0.1</code> ,且设置 <code>protected-mode no</code></li><li>关闭防火墙，或设置密码等方式（可自行搜索）（我的Linux为Centos6，则关闭防火墙：<code>service iptables stop</code>）</li></ul><h3 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h3><ul><li><p>测试连接</p><ul><li><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>redis.clients<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>jedis<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.2.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>测试</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.redis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RedisDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//创建jedis对象</span></span><br><span class="line">        Jedis jedis=<span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.243.129&quot;</span>,<span class="number">6379</span>);</span><br><span class="line">        <span class="comment">//测试连接</span></span><br><span class="line">        String log=jedis.ping();</span><br><span class="line">        <span class="comment">// 成功则会输出pong</span></span><br><span class="line">        System.out.println(log);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul></li><li><p>测试操作</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test01</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//创建jedis对象</span></span><br><span class="line">    Jedis jedis=<span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.243.129&quot;</span>,<span class="number">6379</span>);</span><br><span class="line">    jedis.set(<span class="string">&quot;k1&quot;</span>, <span class="string">&quot;v1&quot;</span>);</span><br><span class="line">    jedis.set(<span class="string">&quot;k2&quot;</span>, <span class="string">&quot;v2&quot;</span>);</span><br><span class="line">    jedis.set(<span class="string">&quot;k3&quot;</span>, <span class="string">&quot;v3&quot;</span>);</span><br><span class="line">    System.out.println(jedis.exists(<span class="string">&quot;k1&quot;</span>));</span><br><span class="line">    System.out.println(jedis.type(<span class="string">&quot;k1&quot;</span>));</span><br><span class="line">    System.out.println(jedis.get(<span class="string">&quot;k1&quot;</span>));</span><br><span class="line">    Set&lt;String&gt; keys = jedis.keys(<span class="string">&quot;*&quot;</span>);</span><br><span class="line">    System.out.println(keys.size());</span><br><span class="line">    <span class="keyword">for</span> (String key : keys) &#123;</span><br><span class="line">        System.out.println(key);</span><br><span class="line">    &#125;</span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">demo02</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Jedis jedis=<span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.243.129&quot;</span>,<span class="number">6379</span>);</span><br><span class="line">    jedis.mset(<span class="string">&quot;str1&quot;</span>,<span class="string">&quot;v1&quot;</span>,<span class="string">&quot;str2&quot;</span>,<span class="string">&quot;v2&quot;</span>,<span class="string">&quot;str3&quot;</span>,<span class="string">&quot;v3&quot;</span>);</span><br><span class="line">    System.out.println(jedis.mget(<span class="string">&quot;str1&quot;</span>,<span class="string">&quot;str2&quot;</span>,<span class="string">&quot;str3&quot;</span>));</span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">demo03</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Jedis jedis=<span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.243.129&quot;</span>,<span class="number">6379</span>);</span><br><span class="line">    jedis.hset(<span class="string">&quot;hash1&quot;</span>,<span class="string">&quot;userName&quot;</span>,<span class="string">&quot;lisi&quot;</span>);</span><br><span class="line">    System.out.println(jedis.hget(<span class="string">&quot;hash1&quot;</span>,<span class="string">&quot;userName&quot;</span>));</span><br><span class="line">    Map&lt;String,String&gt; map = <span class="keyword">new</span> HashMap&lt;String,String&gt;();</span><br><span class="line">    map.put(<span class="string">&quot;telphone&quot;</span>,<span class="string">&quot;13810169999&quot;</span>);</span><br><span class="line">    map.put(<span class="string">&quot;address&quot;</span>,<span class="string">&quot;atguigu&quot;</span>);</span><br><span class="line">    map.put(<span class="string">&quot;email&quot;</span>,<span class="string">&quot;abc@163.com&quot;</span>);</span><br><span class="line">    jedis.hmset(<span class="string">&quot;hash2&quot;</span>,map);</span><br><span class="line">    List&lt;String&gt; result = jedis.hmget(<span class="string">&quot;hash2&quot;</span>, <span class="string">&quot;telphone&quot;</span>,<span class="string">&quot;email&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (String element : result) &#123;</span><br><span class="line">        System.out.println(element);</span><br><span class="line">    &#125;</span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="验证码案例"><a href="#验证码案例" class="headerlink" title="验证码案例"></a>验证码案例</h3><ul><li><p>输入手机号，点击发送后随机生成6位数字码，2分钟有效</p></li><li><p>输入验证码，点击验证，返回成功或失败</p></li><li><p>每个手机号每天只能输入3次</p></li><li><p>存在不足之处，仅作为学习案例</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.redis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"><span class="keyword">import</span> java.util.Random;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhoneCode</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//先执行1</span></span><br><span class="line">        <span class="comment">//verifyCode(&quot;13243129626&quot;);</span></span><br><span class="line">        <span class="comment">//再执行2</span></span><br><span class="line">        checkCode(<span class="string">&quot;13243129626&quot;</span>,<span class="string">&quot;085292&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//生成6位数字验证码</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">getCode</span><span class="params">()</span></span>&#123;</span><br><span class="line">        Random random=<span class="keyword">new</span> Random();</span><br><span class="line">        StringBuilder code= <span class="keyword">new</span> StringBuilder();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">6</span>;i++)&#123;</span><br><span class="line">            code.append(random.nextInt(<span class="number">10</span>));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> code.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//验证码存储到redis中并设置过期时间,最多验证三次</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">verifyCode</span><span class="params">(String phone)</span></span>&#123;</span><br><span class="line">        <span class="comment">//连接</span></span><br><span class="line">        Jedis jedis=<span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.243.129&quot;</span>,<span class="number">6379</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//拼接key</span></span><br><span class="line">        <span class="comment">//验证次数</span></span><br><span class="line">        String countKey=phone+<span class="string">&quot;:count&quot;</span>;</span><br><span class="line">        <span class="comment">//验证码</span></span><br><span class="line">        String codeKey=phone+<span class="string">&quot;:code&quot;</span>;</span><br><span class="line"></span><br><span class="line">        String count=jedis.get(countKey);</span><br><span class="line">        <span class="keyword">if</span>(count==<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="comment">//第一次发送，则设置发送次数为1</span></span><br><span class="line">            jedis.setex(countKey,<span class="number">24</span>*<span class="number">60</span>*<span class="number">60</span>,<span class="string">&quot;1&quot;</span>);</span><br><span class="line">            <span class="comment">//发送验证码并存储</span></span><br><span class="line">            jedis.setex(codeKey,<span class="number">2</span>*<span class="number">60</span>,getCode());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(Integer.parseInt(count)&lt;=<span class="number">2</span>)&#123;</span><br><span class="line">            jedis.incr(countKey);</span><br><span class="line">            <span class="comment">//发送验证码并存储</span></span><br><span class="line">            jedis.setex(codeKey,<span class="number">2</span>*<span class="number">60</span>,getCode());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;您的发送次数已经超过三次！&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        jedis.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">checkCode</span><span class="params">(String phone,String code)</span></span>&#123;</span><br><span class="line">        <span class="comment">//连接</span></span><br><span class="line">        Jedis jedis=<span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.243.129&quot;</span>,<span class="number">6379</span>);</span><br><span class="line">        String j_code=jedis.get(phone+<span class="string">&quot;:code&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span>(j_code.equals(code))&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;ok!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span>&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;error!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        jedis.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="Spring-Boot整合-Redis"><a href="#Spring-Boot整合-Redis" class="headerlink" title="Spring Boot整合 Redis"></a>Spring Boot整合 Redis</h2><ul><li><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></pre></td><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-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="comment">&lt;!-- redis --&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-data-redis<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;!-- spring2.X集成redis所需common-pool2--&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.apache.commons<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>commons-pool2<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.6.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-databind<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.8.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><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></pre></td></tr></table></figure></li><li><p>application.properties配置</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#Redis服务器地址</span></span><br><span class="line"><span class="meta">spring.redis.host</span>=<span class="string">192.168.243.129</span></span><br><span class="line"><span class="comment">#Redis服务器连接端口</span></span><br><span class="line"><span class="meta">spring.redis.port</span>=<span class="string">6379</span></span><br><span class="line"><span class="comment">#Redis数据库索引（默认为0）</span></span><br><span class="line"><span class="meta">spring.redis.database</span>= <span class="string">0</span></span><br><span class="line"><span class="comment">#连接超时时间（毫秒）</span></span><br><span class="line"><span class="meta">spring.redis.timeout</span>=<span class="string">1800000</span></span><br><span class="line"><span class="comment">#连接池最大连接数（使用负值表示没有限制）</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.max-active</span>=<span class="string">20</span></span><br><span class="line"><span class="comment">#最大阻塞等待时间(负数表示没限制)</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.max-wait</span>=<span class="string">-1</span></span><br><span class="line"><span class="comment">#连接池中的最大空闲连接</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.max-idle</span>=<span class="string">5</span></span><br><span class="line"><span class="comment">#连接池中的最小空闲连接</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.min-idle</span>=<span class="string">0</span></span><br></pre></td></tr></table></figure></li><li><p>添加redis配置类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.redis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.annotation.JsonAutoDetect;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.annotation.PropertyAccessor;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cache.CacheManager;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cache.annotation.CachingConfigurerSupport;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cache.annotation.EnableCaching;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.cache.RedisCacheConfiguration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.cache.RedisCacheManager;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.connection.RedisConnectionFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.RedisSerializationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.RedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.StringRedisSerializer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.Duration;</span><br><span class="line"></span><br><span class="line"><span class="meta">@EnableCaching</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RedisConfig</span> <span class="keyword">extends</span> <span class="title">CachingConfigurerSupport</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> RedisTemplate&lt;String, Object&gt; <span class="title">redisTemplate</span><span class="params">(RedisConnectionFactory factory)</span> </span>&#123;</span><br><span class="line">        RedisTemplate&lt;String, Object&gt; template = <span class="keyword">new</span> RedisTemplate&lt;&gt;();</span><br><span class="line">        RedisSerializer&lt;String&gt; redisSerializer = <span class="keyword">new</span> StringRedisSerializer();</span><br><span class="line">        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = <span class="keyword">new</span> Jackson2JsonRedisSerializer(Object.class);</span><br><span class="line">        ObjectMapper om = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line">        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);</span><br><span class="line">        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);</span><br><span class="line">        jackson2JsonRedisSerializer.setObjectMapper(om);</span><br><span class="line">        template.setConnectionFactory(factory);</span><br><span class="line"><span class="comment">//key序列化方式</span></span><br><span class="line">        template.setKeySerializer(redisSerializer);</span><br><span class="line"><span class="comment">//value序列化</span></span><br><span class="line">        template.setValueSerializer(jackson2JsonRedisSerializer);</span><br><span class="line"><span class="comment">//value hashmap序列化</span></span><br><span class="line">        template.setHashValueSerializer(jackson2JsonRedisSerializer);</span><br><span class="line">        <span class="keyword">return</span> template;</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="function"><span class="keyword">public</span> CacheManager <span class="title">cacheManager</span><span class="params">(RedisConnectionFactory factory)</span> </span>&#123;</span><br><span class="line">        RedisSerializer&lt;String&gt; redisSerializer = <span class="keyword">new</span> StringRedisSerializer();</span><br><span class="line">        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = <span class="keyword">new</span> Jackson2JsonRedisSerializer(Object.class);</span><br><span class="line"><span class="comment">//解决查询缓存转换异常的问题</span></span><br><span class="line">        ObjectMapper om = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line">        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);</span><br><span class="line">        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);</span><br><span class="line">        jackson2JsonRedisSerializer.setObjectMapper(om);</span><br><span class="line"><span class="comment">// 配置序列化（解决乱码的问题）,过期时间600秒</span></span><br><span class="line">        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()</span><br><span class="line">                .entryTtl(Duration.ofSeconds(<span class="number">600</span>))</span><br><span class="line">                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))</span><br><span class="line">                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))</span><br><span class="line">                .disableCachingNullValues();</span><br><span class="line">        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)</span><br><span class="line">                .cacheDefaults(config)</span><br><span class="line">                .build();</span><br><span class="line">        <span class="keyword">return</span> cacheManager;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>测试</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.redis;</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.data.redis.core.RedisTemplate;</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;/redisTest&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RedisTestController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> RedisTemplate&lt;String, String&gt; redisTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/1&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">testRedis</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//设置值到redis</span></span><br><span class="line">        redisTemplate.opsForValue().set(<span class="string">&quot;name&quot;</span>,<span class="string">&quot;lucy&quot;</span>);</span><br><span class="line">        <span class="comment">//从redis获取值</span></span><br><span class="line">        String name = redisTemplate.opsForValue().get(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">        System.out.println(name);</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h2><p>Redis事务是一个单独的隔离操作：事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中，不会被其他客户端发送来的命令请求所打断。Redis事务的主要作用就是<strong>串联多个命令防止别的命令插队</strong>。</p><h3 id="Multi、Exec、discard"><a href="#Multi、Exec、discard" class="headerlink" title="Multi、Exec、discard"></a>Multi、Exec、discard</h3><ul><li>从输入<strong>Multi</strong>命令开始，输入的命令都会依次进入命令队列中，但不会执行，直到输入<strong>Exec</strong>后，Redis会将之前的命令队列中的命令依次执行。</li><li>组队的过程中可以通过<strong>discard</strong>来放弃组队。  </li></ul><h3 id="事务的错误处理"><a href="#事务的错误处理" class="headerlink" title="事务的错误处理"></a>事务的错误处理</h3><ul><li><strong>组队</strong>中某个命令出现了报告错误，执行时整个的所有队列都会被取消</li><li><strong>执行</strong>阶段某个命令报出了错误，则只有报错的命令不会被执行，而其他的命令都会执行，不会回滚</li></ul><h3 id="悲观锁"><a href="#悲观锁" class="headerlink" title="悲观锁"></a>悲观锁</h3><p>​    悲观锁就是很悲观，每次去拿数据的时候都认为别人会修改，所以每次在拿数据的时候都会上锁，这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制，比如行锁，表锁等，读锁，写锁等，都是在做操作之前先上锁。</p><h3 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h3><p>​    乐观锁就是很乐观，每次去拿数据的时候都认为别人不会修改，所以不会上锁，但是在更新的时候会判断一下在此期间别人有没有去更新这个数据，可以使用<strong>版本号</strong>等机制。乐观锁适用于多读的应用类型，这样可以提高吞吐量。Redis就是利用这种机制实现事务的。</p><h3 id="特性"><a href="#特性" class="headerlink" title="特性"></a>特性</h3><ul><li>单独的隔离操作<ul><li>事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中，不会被其他客户端发送来的命令请求所打断。 </li></ul></li><li>没有隔离级别的概念<ul><li>队列中的命令没有提交之前都不会实际被执行，因为事务提交前任何指令都不会被实际执行</li></ul></li><li>不保证原子性<ul><li>事务中如果有一条命令执行失败，其后的命令仍然会被执行，没有回滚</li></ul></li></ul><h2 id="持久化"><a href="#持久化" class="headerlink" title="持久化"></a>持久化</h2><h3 id="RDB"><a href="#RDB" class="headerlink" title="RDB"></a>RDB</h3><ul><li><p>在指定的时间间隔内将内存中的数据集快照写入磁盘</p></li><li><p>Redis会单独创建（fork）一个子进程来进行持久化，会先将数据写入到 一个临时文件中，待持久化过程都结束了，再用这个临时文件替换上次持久化好的文件。 整个过程中，主进程是不进行任何IO操作的，这就确保了极高的性能 如果需要进行大规模数据的恢复，且对于数据恢复的完整性不是非常敏感，那RDB方式要比AOF方式更加的高效。RDB的缺点是<strong>最后一次持久化后的数据可能丢失</strong>。</p></li><li><p>一般情况父进程和子进程会共用同一段物理内存，只有进程空间的各段的内容要发生变化时，才会将父进程的内容复制一份给子进程。</p></li><li><p>优势</p><ul><li>适合大规模的数据恢复</li><li>对数据完整性和一致性要求不高更适合使用</li><li>节省磁盘空间</li><li>恢复速度快</li></ul></li><li><p>劣势</p><ul><li>Fork的时候，内存中的数据被克隆了一份，大致2倍的膨胀性需要考虑</li><li>虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。</li><li>如果Redis意外down掉的话，就会丢失最后一次快照后的所有修改</li></ul></li></ul><h3 id="AOF"><a href="#AOF" class="headerlink" title="AOF"></a>AOF</h3><p>​    以日志的形式来记录每个写操作（增量保存），将Redis执行过的所有写指令记录下来(读操作不记录)。换言之，redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。</p><ul><li>AOF默认不开启</li><li>AOF和RDB同时开启，系统默认取AOF的数据（数据不会存在丢失）</li><li>优势<ul><li>备份机制更稳健，丢失数据概率更低</li><li>可读的日志文本，可以处理误操作</li></ul></li><li>劣势<ul><li>比起RDB占用更多的磁盘空间</li><li>每次写都同步的话，有一定的性能压力</li><li>恢复备份速度要慢</li></ul></li></ul><h2 id="主从复制"><a href="#主从复制" class="headerlink" title="主从复制"></a>主从复制</h2><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><ul><li>主机数据更新后根据配置和策略， 自动同步到备机的master/slaver机制，Master以写为主，Slave以读为主<ul><li>读写分离，性能扩展</li><li>容灾快速恢复</li></ul></li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-23_17-45-28.jpg" alt="20201019172422525.jpg"></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-23_18-05-47.jpg" alt="20201019172422525.jpg"></p><h2 id="集群"><a href="#集群" class="headerlink" title="集群"></a>集群</h2><h3 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h3><ul><li>Redis 集群实现了对Redis的水平扩容，即启动N个redis节点，将整个数据库分布存储在这N个节点中，每个节点存储总数据的1/N。</li><li>Redis 集群通过分区来提供一定程度的可用性： 即使集群中有一部分节点失效或者无法进行通讯， 集群也可以继续处理命令请求。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-23_18-52-58.jpg" alt="20201019172422525.jpg"></p>]]></content>
    
    
    <summary type="html">Redis，即远程字典服务，是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库，并提供多种语言的API。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>SpringCache+Redis实现缓存</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/19/SpringCache+Redis%E5%AE%9E%E7%8E%B0%E7%BC%93%E5%AD%98/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/19/SpringCache+Redis%E5%AE%9E%E7%8E%B0%E7%BC%93%E5%AD%98/</id>
    <published>2022-01-19T08:36:59.317Z</published>
    <updated>2022-02-26T02:29:41.853Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>​    Spring Cache 是一个非常优秀的缓存组件。自Spring 3.1起，提供了类似于@Transactional注解事务的注解Cache支持，且提供了Cache抽象，方便切换各种底层Cache（如：redis），好处有：</p><ul><li>提供基本的Cache抽象，方便切换各种底层Cache；</li><li>通过注解Cache可以实现类似于事务一样，缓存逻辑透明的应用到我们的业务代码上，且只需要更少的代码就可以完成；</li><li>提供事务回滚时也自动回滚缓存；</li><li>支持比较复杂的缓存逻辑；</li></ul><h2 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h2><h3 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- redis --&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-data-redis<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="comment">&lt;!-- spring2.X集成redis所需common-pool2--&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.apache.commons<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>commons-pool2<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.6.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="添加Redis配置类"><a href="#添加Redis配置类" class="headerlink" title="添加Redis配置类"></a>添加Redis配置类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.common.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.annotation.JsonAutoDetect;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.annotation.PropertyAccessor;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cache.CacheManager;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cache.annotation.EnableCaching;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cache.interceptor.KeyGenerator;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.cache.RedisCacheConfiguration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.cache.RedisCacheManager;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.connection.RedisConnectionFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.RedisSerializationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.RedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.StringRedisSerializer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.time.Duration;</span><br><span class="line"></span><br><span class="line"><span class="comment">//标明配置类</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="comment">//允许缓存</span></span><br><span class="line"><span class="meta">@EnableCaching</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RedisConfig</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 自定义key规则</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> KeyGenerator <span class="title">keyGenerator</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> KeyGenerator() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> Object <span class="title">generate</span><span class="params">(Object target, Method method, Object... params)</span> </span>&#123;</span><br><span class="line">                StringBuilder sb = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">                sb.append(target.getClass().getName());</span><br><span class="line">                sb.append(method.getName());</span><br><span class="line">                <span class="keyword">for</span> (Object obj : params) &#123;</span><br><span class="line">                    sb.append(obj.toString());</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> sb.toString();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置RedisTemplate规则</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> redisConnectionFactory</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> RedisTemplate&lt;Object, Object&gt; <span class="title">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> </span>&#123;</span><br><span class="line">        RedisTemplate&lt;Object, Object&gt; redisTemplate = <span class="keyword">new</span> RedisTemplate&lt;&gt;();</span><br><span class="line">        redisTemplate.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = <span class="keyword">new</span> Jackson2JsonRedisSerializer(Object.class);</span><br><span class="line"></span><br><span class="line"><span class="comment">//解决查询缓存转换异常的问题</span></span><br><span class="line">        ObjectMapper om = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line"><span class="comment">// 指定要序列化的域，field,get和set,以及修饰符范围，ANY是都有包括private和public</span></span><br><span class="line">        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);</span><br><span class="line"><span class="comment">// 指定序列化输入的类型，类必须是非final修饰的，final修饰的类，比如String,Integer等会跑出异常</span></span><br><span class="line">        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);</span><br><span class="line">        jackson2JsonRedisSerializer.setObjectMapper(om);</span><br><span class="line"></span><br><span class="line"><span class="comment">//序列号key value</span></span><br><span class="line">        redisTemplate.setKeySerializer(<span class="keyword">new</span> StringRedisSerializer());</span><br><span class="line">        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);</span><br><span class="line">        redisTemplate.setHashKeySerializer(<span class="keyword">new</span> StringRedisSerializer());</span><br><span class="line">        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);</span><br><span class="line"></span><br><span class="line">        redisTemplate.afterPropertiesSet();</span><br><span class="line">        <span class="keyword">return</span> redisTemplate;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置CacheManager缓存规则</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> factory</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> CacheManager <span class="title">cacheManager</span><span class="params">(RedisConnectionFactory factory)</span> </span>&#123;</span><br><span class="line">        RedisSerializer&lt;String&gt; redisSerializer = <span class="keyword">new</span> StringRedisSerializer();</span><br><span class="line">        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = <span class="keyword">new</span> Jackson2JsonRedisSerializer(Object.class);</span><br><span class="line"></span><br><span class="line"><span class="comment">//解决查询缓存转换异常的问题</span></span><br><span class="line">        ObjectMapper om = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line">        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);</span><br><span class="line">        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);</span><br><span class="line">        jackson2JsonRedisSerializer.setObjectMapper(om);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 配置序列化（解决乱码的问题）,过期时间600秒</span></span><br><span class="line">        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()</span><br><span class="line">                .entryTtl(Duration.ofSeconds(<span class="number">600</span>))</span><br><span class="line">                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))</span><br><span class="line">                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))</span><br><span class="line">                .disableCachingNullValues();</span><br><span class="line"></span><br><span class="line">        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)</span><br><span class="line">                .cacheDefaults(config)</span><br><span class="line">                .build();</span><br><span class="line">        <span class="keyword">return</span> cacheManager;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Redis配置"><a href="#Redis配置" class="headerlink" title="Redis配置"></a>Redis配置</h3><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">#redisw配置</span></span><br><span class="line"><span class="meta">spring.redis.host</span>=<span class="string">192.168.243.129</span></span><br><span class="line"><span class="meta">spring.redis.port</span>=<span class="string">6379</span></span><br><span class="line"><span class="meta">spring.redis.database</span>= <span class="string">0</span></span><br><span class="line"><span class="meta">spring.redis.timeout</span>=<span class="string">1800000</span></span><br><span class="line"></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.max-active</span>=<span class="string">20</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.max-wait</span>=<span class="string">-1</span></span><br><span class="line"><span class="comment">#最大阻塞等待时间(负数表示没限制)</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.max-idle</span>=<span class="string">5</span></span><br><span class="line"><span class="meta">spring.redis.lettuce.pool.min-idle</span>=<span class="string">0</span></span><br></pre></td></tr></table></figure><h3 id="使用Spring-Cache"><a href="#使用Spring-Cache" class="headerlink" title="使用Spring Cache"></a>使用Spring Cache</h3><ul><li><p>@Cacheable：根据方法对其返回结果进行缓存，下次请求时，如果缓存存在，则直接读取缓存数据返回；如果缓存不存在，则执行方法，并把返回的结果存入缓存中。一般用在查询方法上。</p><ul><li><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">value<span class="comment">#缓存名，必填，它指定了你的缓存存放在哪块命名空间,用于在redis中生成key</span></span><br></pre></td></tr></table></figure></li></ul></li><li><p>@CachePut：使用该注解标志的方法，每次都会执行，并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据，而不需要再去查询数据库。一般用在新增方法上。属性同上</p></li><li><p>@CacheEvict：使用该注解标志的方法，会清空指定的缓存。一般用在更新或者删除方法上，属性同上</p></li></ul><h4 id="数据字典中应用"><a href="#数据字典中应用" class="headerlink" title="数据字典中应用"></a>数据字典中应用</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DictServiceImpl</span> <span class="keyword">extends</span> <span class="title">ServiceImpl</span>&lt;<span class="title">DictMapper</span>, <span class="title">Dict</span>&gt; <span class="keyword">implements</span> <span class="title">DictService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@Cacheable(value = &quot;dict&quot;,keyGenerator = &quot;keyGenerator&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;Dict&gt; <span class="title">findChildData</span><span class="params">(<span class="keyword">long</span> id)</span> </span>&#123;</span><br><span class="line">        QueryWrapper&lt;Dict&gt; wrapper=<span class="keyword">new</span> QueryWrapper&lt;&gt;();</span><br><span class="line">        wrapper.eq(<span class="string">&quot;parent_id&quot;</span>,id);</span><br><span class="line">        List&lt;Dict&gt; dictList=baseMapper.selectList(wrapper);</span><br><span class="line">        <span class="keyword">for</span>(Dict dict:dictList)&#123;</span><br><span class="line">            Long dictId=dict.getId();</span><br><span class="line">            <span class="keyword">boolean</span> isChild=<span class="keyword">this</span>.hasChildren(dictId);</span><br><span class="line">            dict.setHasChildren(isChild);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dictList;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@CacheEvict(value = &quot;dict&quot;, allEntries=true)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">importDictData</span><span class="params">(MultipartFile file)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            EasyExcel.read(file.getInputStream(), DictEeVo.class,<span class="keyword">new</span> DictListener(baseMapper)).sheet().doRead();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (IOException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">Spring Cache 是一个非常优秀的缓存组件。其提供了Cache抽象，方便切换各种底层Cache（如：redis）。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>快速上手EasyExcel</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/17/%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8BEasyExcel/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/17/%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8BEasyExcel/</id>
    <published>2022-01-17T09:42:13.396Z</published>
    <updated>2022-10-09T14:39:04.636Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="EasyExcel简介"><a href="#EasyExcel简介" class="headerlink" title="EasyExcel简介"></a>EasyExcel简介</h2><p>​    Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存。</p><p>​    EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel文件。</p><h2 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h2><h3 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</h3><ul><li><p>在pom文件中加入依赖</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --&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<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>easyexcel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="创建实体类"><a href="#创建实体类" class="headerlink" title="创建实体类"></a>创建实体类</h3><ul><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.EasyExcel;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.excel.annotation.ExcelProperty;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</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="class"><span class="keyword">class</span> <span class="title">UserData</span> </span>&#123;</span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户编号&quot;,index = 0)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> uid;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户名称&quot;,index = 1)</span></span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="数据写操作"><a href="#数据写操作" class="headerlink" title="数据写操作"></a>数据写操作</h3><ul><li><p>将数据写入到excel文件中</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.EasyExcel;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.excel.EasyExcel;</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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">testWrite</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//构造数据集合</span></span><br><span class="line">        List&lt;UserData&gt; userData=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">100</span>;i++)&#123;</span><br><span class="line">            UserData userData1=<span class="keyword">new</span> UserData();</span><br><span class="line">            userData1.setUid(i);</span><br><span class="line">            userData1.setUsername(<span class="string">&quot;xlh&quot;</span>+i);</span><br><span class="line">            userData.add(userData1);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//设置excel文件路径及名称</span></span><br><span class="line">        String fileName=<span class="string">&quot;D:\\01.xlsx&quot;</span>;</span><br><span class="line">        <span class="comment">//进行写操作</span></span><br><span class="line">        EasyExcel.write(fileName,UserData.class).sheet(<span class="string">&quot;用户列表&quot;</span>).doWrite(userData);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>运行结果</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-17_18-09-42.jpg" alt="20201028131432875.png"></p></li></ul><h3 id="数据读操作"><a href="#数据读操作" class="headerlink" title="数据读操作"></a>数据读操作</h3><ul><li><p>将excel数据读出</p></li><li><p>首先继承AnalysisEventListener类</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.xlh.EasyExcel;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.excel.context.AnalysisContext;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.excel.event.AnalysisEventListener;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExcelListener</span> <span class="keyword">extends</span> <span class="title">AnalysisEventListener</span>&lt;<span class="title">UserData</span>&gt; </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">invoke</span><span class="params">(UserData userData, AnalysisContext analysisContext)</span> </span>&#123;</span><br><span class="line">        System.out.println(userData);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">invokeHeadMap</span><span class="params">(Map&lt;Integer, String&gt; headMap, AnalysisContext context)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;表头信息：&quot;</span>+headMap);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doAfterAllAnalysed</span><span class="params">(AnalysisContext analysisContext)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;finished!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.EasyExcel;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.excel.EasyExcel;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestListener</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//excel的路径</span></span><br><span class="line">        String filename=<span class="string">&quot;D:\\01.xlsx&quot;</span>;</span><br><span class="line">        <span class="comment">//读取</span></span><br><span class="line">        EasyExcel.read(filename,UserData.class,<span class="keyword">new</span> ExcelListener()).sheet().doRead();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>结果</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-17_20-28-44.jpg" alt="20201028131432875.png"></p></li></ul></li></ul>]]></content>
    
    
    <summary type="html">EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>Swagger-接口文档利器</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/11/Swagger-%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3%E5%88%A9%E5%99%A8/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/11/Swagger-%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3%E5%88%A9%E5%99%A8/</id>
    <published>2022-01-11T13:38:57.968Z</published>
    <updated>2022-02-26T02:26:59.095Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><ul><li>Swagger支持 API 自动生成同步的在线文档：使用 Swagger 后可以直接通过代码生成文档，不再需要自己手动编写接口文档了</li><li>提供 Web 页面在线测试 API：光有文档还不够，Swagger 生成的文档还支持在线测试</li></ul><h2 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h2><p>​    下面将给出在SpringBoot2项目中使用Swagger的基本步骤，这里将Swagger配置类单独拿出，作为公共配置部分。</p><h3 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</h3><ul><li><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></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--swagger--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.springfox<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>springfox-swagger2<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.springfox<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>springfox-swagger-ui<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></li></ul><h3 id="添加配置类"><a href="#添加配置类" class="headerlink" title="添加配置类"></a>添加配置类</h3>  <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.common.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.google.common.base.Predicates;</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> springfox.documentation.builders.ApiInfoBuilder;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.builders.PathSelectors;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.service.ApiInfo;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.service.Contact;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.spi.DocumentationType;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.spring.web.plugins.Docket;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.swagger2.annotations.EnableSwagger2;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Swagger2配置信息</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableSwagger2</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Swagger2Config</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Docket <span class="title">webApiConfig</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Docket(DocumentationType.SWAGGER_2)</span><br><span class="line">                .groupName(<span class="string">&quot;webApi&quot;</span>)</span><br><span class="line">                .apiInfo(webApiInfo())</span><br><span class="line">                .select()</span><br><span class="line">                <span class="comment">//只显示api路径下的页面</span></span><br><span class="line">                .paths(Predicates.and(PathSelectors.regex(<span class="string">&quot;/api/.*&quot;</span>)))</span><br><span class="line">                .build();</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="function"><span class="keyword">public</span> Docket <span class="title">adminApiConfig</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Docket(DocumentationType.SWAGGER_2)</span><br><span class="line">                .groupName(<span class="string">&quot;adminApi&quot;</span>)</span><br><span class="line">                .apiInfo(adminApiInfo())</span><br><span class="line">                .select()</span><br><span class="line">                <span class="comment">//只显示admin路径下的页面</span></span><br><span class="line">                .paths(Predicates.and(PathSelectors.regex(<span class="string">&quot;/admin/.*&quot;</span>)))</span><br><span class="line">                .build();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> ApiInfo <span class="title">webApiInfo</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ApiInfoBuilder()</span><br><span class="line">                .title(<span class="string">&quot;网站-API文档&quot;</span>)</span><br><span class="line">                .description(<span class="string">&quot;本文档描述了网站微服务接口定义&quot;</span>)</span><br><span class="line">                .version(<span class="string">&quot;1.0&quot;</span>)</span><br><span class="line">                .contact(<span class="keyword">new</span> Contact(<span class="string">&quot;xlh&quot;</span>, <span class="string">&quot;http://xlh.com&quot;</span>, <span class="string">&quot;1583677918@qq.com&quot;</span>))</span><br><span class="line">                .build();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">private</span> ApiInfo <span class="title">adminApiInfo</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ApiInfoBuilder()</span><br><span class="line">                .title(<span class="string">&quot;后台管理系统-API文档&quot;</span>)</span><br><span class="line">                .description(<span class="string">&quot;本文档描述了后台管理系统微服务接口定义&quot;</span>)</span><br><span class="line">                .version(<span class="string">&quot;1.0&quot;</span>)</span><br><span class="line">                .contact(<span class="keyword">new</span> Contact(<span class="string">&quot;xlh&quot;</span>, <span class="string">&quot;http://xlh.com&quot;</span>, <span class="string">&quot;1583677918@qq.com&quot;</span>))</span><br><span class="line">                .build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="启动类扫描"><a href="#启动类扫描" class="headerlink" title="启动类扫描"></a>启动类扫描</h3><ul><li><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.xlh<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>service_util<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">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.hosp;</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.context.annotation.ComponentScan;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="comment">// 扫描自己和导入的所有包</span></span><br><span class="line"><span class="meta">@ComponentScan(basePackages = &quot;com.xlh&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServiceHospApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(ServiceHospApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="注释"><a href="#注释" class="headerlink" title="注释"></a>注释</h3><ul><li><p>可在controller中添加接口说明</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.yygh.hosp.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.xlh.yygh.hosp.service.HospitalSetService;</span><br><span class="line"><span class="keyword">import</span> com.xlh.yygh.model.hosp.HospitalSet;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.Api;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiOperation;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Api(tags = &quot;医院设置管理&quot;)</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/admin/hosp/hospitalSet&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HospitalSetController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> HospitalSetService hospitalSetService;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//查找表内所有数据</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;获取所有医院设置&quot;)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/findAll&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;HospitalSet&gt; <span class="title">findAll</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> hospitalSetService.list();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//根据删除id删除数据</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;根据id逻辑删除医院设置&quot;)</span></span><br><span class="line">    <span class="meta">@DeleteMapping(&quot;&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">removeHospSet</span><span class="params">(<span class="meta">@PathVariable</span> Long id)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> hospitalSetService.removeById(id);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><ul><li><p>运行项目，在浏览器打开链接<code>http://localhost:8201/swagger-ui.html</code></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-11_22-02-06.jpg" alt="01.jpg"></p></li><li><p>测试查询</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-11_22-10-25.jpg" alt="01.jpg"></p></li><li><p>测试删除</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-11_22-11-13.jpg" alt="01.jpg"></p></li></ul><p>m</p>]]></content>
    
    
    <summary type="html">Swagger是一款为接口文档而生的框架，可以高效地生成API文档，并提供在线调试等功能。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>MyBatisPlus入门</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/09/MyBatisPlus%E5%85%A5%E9%97%A8/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/09/MyBatisPlus%E5%85%A5%E9%97%A8/</id>
    <published>2022-01-09T09:17:05.789Z</published>
    <updated>2022-02-26T02:26:16.740Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="预览"><a href="#预览" class="headerlink" title="预览"></a>预览</h2><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-02-10_16-12-38.jpg" alt="20210121192316851.png"></p><h2 id="入门案例"><a href="#入门案例" class="headerlink" title="入门案例"></a>入门案例</h2><ul><li>创建SpringBoot项目</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-09_20-54-47.jpg" alt="20210121192316851.png"></p><ul><li>导入相关依赖(mysql版本要与配置文件对应，mysql5和mysql8有所区别)</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</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>2.2.1.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">relativePath</span>/&gt;</span> <span class="comment">&lt;!-- lookup parent from repository --&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">groupId</span>&gt;</span>com.xlh<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>mpdemo<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>mpdemo<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>Demo project for Spring Boot<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>1.8<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span 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">exclusions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.junit.vintage<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>junit-vintage-engine<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--mybatis-plus--&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.baomidou<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>mybatis-plus-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">&lt;!--mysql依赖--&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>mysql<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>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.1.47<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--lombok用来简化实体类--&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.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</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">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><ul><li><p>安装Lombok插件，使得简化get/set方法，简洁高效</p></li><li><p>配置<code>application.properties</code>文件(如果mysql&gt;=8.0,则需要加时区，classname也需要更改)</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></pre></td><td class="code"><pre><span class="line"><span class="meta">spring.datasource.driver-class-name</span>=<span class="string">com.mysql.jdbc.Driver</span></span><br><span class="line"><span class="meta">spring.datasource.url</span>=<span class="string">jdbc:mysql://localhost:3306/mybatis_plus</span></span><br><span class="line"><span class="meta">spring.datasource.username</span>=<span class="string">root</span></span><br><span class="line"><span class="meta">spring.datasource.password</span>=<span class="string">root</span></span><br><span class="line"><span class="comment">#mybatis日志</span></span><br><span class="line"><span class="meta">mybatis-plus.configuration.log-impl</span>=<span class="string">org.apache.ibatis.logging.stdout.StdOutImpl</span></span><br></pre></td></tr></table></figure></li><li><p>创建实体类（使用@Data注解简化代码）</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.xlh.mpdemo.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> String email;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>创建mapper</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mpdemo.mapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.mapper.BaseMapper;</span><br><span class="line"><span class="keyword">import</span> com.xlh.mpdemo.entity.User;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Repository;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Repository</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">UserMapper</span> <span class="keyword">extends</span> <span class="title">BaseMapper</span>&lt;<span class="title">User</span>&gt; </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mpdemo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.mybatis.spring.annotation.MapperScan;</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="meta">@MapperScan(&quot;com.xlh.mpdemo.mapper&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MpdemoApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(MpdemoApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>建立数据库及数据表，数据库名为<code>mybatis_plus</code></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="keyword">USER</span></span><br><span class="line">(</span><br><span class="line">    id <span class="type">BIGINT</span>(<span class="number">20</span>)<span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;主键ID&#x27;</span>,</span><br><span class="line">    NAME <span class="type">VARCHAR</span>(<span class="number">30</span>)<span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;姓名&#x27;</span>,</span><br><span class="line">    age <span class="type">INT</span>(<span class="number">11</span>)<span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;年龄&#x27;</span>,</span><br><span class="line">    email <span class="type">VARCHAR</span>(<span class="number">50</span>)<span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;邮箱&#x27;</span>,</span><br><span class="line">    <span class="keyword">PRIMARY</span> KEY (id)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="keyword">user</span> (id, name, age, email)<span class="keyword">VALUES</span></span><br><span class="line">(<span class="number">1</span>, <span class="string">&#x27;Jone&#x27;</span>, <span class="number">18</span>, <span class="string">&#x27;test1@baomidou.com&#x27;</span>),</span><br><span class="line">(<span class="number">2</span>, <span class="string">&#x27;Jack&#x27;</span>, <span class="number">20</span>, <span class="string">&#x27;test2@baomidou.com&#x27;</span>),</span><br><span class="line">(<span class="number">3</span>, <span class="string">&#x27;Tom&#x27;</span>, <span class="number">28</span>, <span class="string">&#x27;test3@baomidou.com&#x27;</span>),</span><br><span class="line">(<span class="number">4</span>, <span class="string">&#x27;Sandy&#x27;</span>, <span class="number">21</span>, <span class="string">&#x27;test4@baomidou.com&#x27;</span>),</span><br><span class="line">(<span class="number">5</span>, <span class="string">&#x27;Billie&#x27;</span>, <span class="number">24</span>, <span class="string">&#x27;test5@baomidou.com&#x27;</span>);</span><br></pre></td></tr></table></figure></li><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mpdemo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.xlh.mpdemo.entity.User;</span><br><span class="line"><span class="keyword">import</span> com.xlh.mpdemo.mapper.UserMapper;</span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.Test;</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.boot.test.context.SpringBootTest;</span><br><span class="line"></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">@SpringBootTest</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MpdemoApplicationTests</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserMapper userMapper;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">findall</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        List&lt;User&gt; users = userMapper.selectList(<span class="keyword">null</span>);</span><br><span class="line">        System.out.println(users);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="添加"><a href="#添加" class="headerlink" title="添加"></a>添加</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testAdd</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    User user = <span class="keyword">new</span> User();</span><br><span class="line">    user.setName(<span class="string">&quot;xiaoming&quot;</span>);</span><br><span class="line">    user.setAge(<span class="number">21</span>);</span><br><span class="line">    user.setEmail(<span class="string">&quot;1234@qq.com&quot;</span>);</span><br><span class="line">    <span class="keyword">int</span> insert = userMapper.insert(user);</span><br><span class="line">    System.out.println(insert);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="主键策略"><a href="#主键策略" class="headerlink" title="主键策略"></a>主键策略</h2><h3 id="ASSIGN-ID"><a href="#ASSIGN-ID" class="headerlink" title="ASSIGN_ID"></a>ASSIGN_ID</h3><p>​    MyBatis-Plus默认的主键策略是：ASSIGN_ID （使用了雪花算法）,雪花算法：分布式ID生成器</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@TableId(type = IdType.ASSIGN_ID)</span></span><br><span class="line"><span class="keyword">private</span> Long id;</span><br></pre></td></tr></table></figure><h3 id="AUTO-自增策略"><a href="#AUTO-自增策略" class="headerlink" title="AUTO 自增策略"></a>AUTO 自增策略</h3><p>​    需要在创建数据表的时候设置主键自增.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@TableId(type = IdType.AUTO)</span></span><br><span class="line"><span class="keyword">private</span> Long id;</span><br></pre></td></tr></table></figure><p>也可设置全局作用：</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mybatis-plus.global-config.db-config.id-type</span>=<span class="string">auto</span></span><br></pre></td></tr></table></figure><h2 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h2><h3 id="修改"><a href="#修改" class="headerlink" title="修改"></a>修改</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testModify</span><span class="params">()</span></span>&#123;</span><br><span class="line">    User user=<span class="keyword">new</span> User();</span><br><span class="line">    user.setId(Long.valueOf(<span class="string">&quot;1&quot;</span>));</span><br><span class="line">    user.setName(<span class="string">&quot;xxx&quot;</span>);</span><br><span class="line">    <span class="keyword">int</span> count = userMapper.updateById(user);</span><br><span class="line">    System.out.println(count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="自动填充"><a href="#自动填充" class="headerlink" title="自动填充"></a>自动填充</h3><ul><li><p>在数据表中添加两个字段：create_time、update_time，类型为datetime</p></li><li><p>在User实体类中对应驼峰命名，并添加注解</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//在插入时自动填充</span></span><br><span class="line"><span class="meta">@TableField(fill = FieldFill.INSERT)</span></span><br><span class="line"><span class="keyword">private</span> Date createTime;</span><br><span class="line"></span><br><span class="line"><span class="comment">//在修改和插入时自动填充</span></span><br><span class="line"><span class="meta">@TableField(fill = FieldFill.INSERT_UPDATE)</span></span><br><span class="line"><span class="keyword">private</span> Date updateTime;</span><br></pre></td></tr></table></figure></li><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mpdemo.handler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Date;</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="class"><span class="keyword">class</span> <span class="title">MyMetaObjectHandler</span> <span class="keyword">implements</span> <span class="title">MetaObjectHandler</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insertFill</span><span class="params">(MetaObject metaObject)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.setFieldValByName(<span class="string">&quot;createTime&quot;</span>,<span class="keyword">new</span> Date(),metaObject);</span><br><span class="line">        <span class="keyword">this</span>.setFieldValByName(<span class="string">&quot;updateTime&quot;</span>,<span class="keyword">new</span> Date(),metaObject);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">updateFill</span><span class="params">(MetaObject metaObject)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.setFieldValByName(<span class="string">&quot;updateTime&quot;</span>,<span class="keyword">new</span> Date(),metaObject);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h3><p><strong>主要适用场景：</strong>当要更新一条记录的时候，希望这条记录没有被别人更新，也就是说实现线程安全的数据更新。</p><p><strong>乐观锁实现方式：</strong></p><ul><li>取出记录时，获取当前version</li><li>更新时，带上这个version</li><li>执行更新时， set version = newVersion where version = oldVersion</li><li>如果version不对，就更新失败</li></ul><h3 id="操作步骤"><a href="#操作步骤" class="headerlink" title="操作步骤"></a>操作步骤</h3><ul><li><p>在数据表中添加字段<code>version</code>,类型为<code>int</code></p></li><li><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></pre></td><td class="code"><pre><span class="line"> <span class="comment">//代表版本号</span></span><br><span class="line"><span class="meta">@Version</span></span><br><span class="line"><span class="keyword">private</span> Integer version;</span><br></pre></td></tr></table></figure></li><li><p>配置乐观锁插件</p><ul><li><p>创建配置类，并注册插件</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xlh.mpdemo.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;</span><br><span class="line"><span class="keyword">import</span> org.mybatis.spring.annotation.MapperScan;</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="comment">//配置类</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@MapperScan(&quot;com.xlh.mpdemo.mapper&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MpConfig</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 乐观锁插件</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> OptimisticLockerInterceptor <span class="title">optimisticLockerInterceptor</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> OptimisticLockerInterceptor();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul></li><li><p>测试乐观琐(更新时，如果版本号符合则成功，版本+1,；否则失败)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testOptimisticLocker</span><span class="params">()</span></span>&#123;</span><br><span class="line">    User user=userMapper.selectById(<span class="number">1480518292787113986L</span>);</span><br><span class="line">    user.setName(<span class="string">&quot;22222&quot;</span>);</span><br><span class="line">    <span class="keyword">int</span> count = userMapper.updateById(user);</span><br><span class="line">    System.out.println(count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h2><ul><li><p>多个id批量查询</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelectByIds</span><span class="params">()</span></span>&#123;</span><br><span class="line">    List&lt;User&gt; users=userMapper.selectBatchIds(Arrays.asList(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>));</span><br><span class="line">    System.out.println(users);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>条件查询</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelect2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Map&lt;String, Object&gt; columnMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    columnMap.put(<span class="string">&quot;name&quot;</span>,<span class="string">&quot;Jack&quot;</span>);</span><br><span class="line">    columnMap.put(<span class="string">&quot;age&quot;</span>,<span class="number">20</span>);</span><br><span class="line">    List&lt;User&gt; users = userMapper.selectByMap(columnMap);</span><br><span class="line">    System.out.println(users);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>分页</p><ul><li><p>在<code>MpConfig</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 分页插件</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> PaginationInterceptor <span class="title">paginationInterceptor</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> PaginationInterceptor();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>测试</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelectPage</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Page&lt;User&gt; page = <span class="keyword">new</span> Page(<span class="number">1</span>,<span class="number">3</span>);</span><br><span class="line">    Page&lt;User&gt; userPage = userMapper.selectPage(page, <span class="keyword">null</span>);</span><br><span class="line">    <span class="comment">//返回对象得到分页所有数据</span></span><br><span class="line">    <span class="keyword">long</span> pages = userPage.getPages(); <span class="comment">//总页数</span></span><br><span class="line">    <span class="keyword">long</span> current = userPage.getCurrent(); <span class="comment">//当前页</span></span><br><span class="line">    List&lt;User&gt; records = userPage.getRecords(); <span class="comment">//查询数据集合</span></span><br><span class="line">    <span class="keyword">long</span> total = userPage.getTotal(); <span class="comment">//总记录数</span></span><br><span class="line">    <span class="keyword">boolean</span> hasNext = userPage.hasNext();  <span class="comment">//下一页</span></span><br><span class="line">    <span class="keyword">boolean</span> hasPrevious = userPage.hasPrevious(); <span class="comment">//上一页</span></span><br><span class="line">    System.out.println(pages);</span><br><span class="line">    System.out.println(current);</span><br><span class="line">    System.out.println(records);</span><br><span class="line">    System.out.println(total);</span><br><span class="line">    System.out.println(hasNext);</span><br><span class="line">    System.out.println(hasPrevious);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul></li></ul><h2 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h2><ul><li><p>根据id删除</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testDeleteById</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> result = userMapper.deleteById(<span class="number">5L</span>);</span><br><span class="line">    System.out.println(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>根据id批量删除</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testDeleteBatchIds</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> result = userMapper.deleteBatchIds(Arrays.asList(<span class="number">1</span>,<span class="number">2</span>));</span><br><span class="line">    System.out.println(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>条件删除</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testDeleteByMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    HashMap&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    map.put(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;Tom&quot;</span>);</span><br><span class="line">    map.put(<span class="string">&quot;age&quot;</span>, <span class="number">28</span>);</span><br><span class="line">    <span class="keyword">int</span> result = userMapper.deleteByMap(map);</span><br><span class="line">    System.out.println(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>逻辑删除和物理删除</p><ul><li>物理删除：真实删除，将对应数据从数据库中删除，之后查询不到此条被删除数据</li><li>逻辑删除：假删除，将对应数据中代表是否被删除字段状态修改为“被删除状态”，之后在数据库中仍旧能看到此条数据记录</li></ul></li><li><p>逻辑删除实现</p><ul><li><p>数据表中添加字段<code>deleted</code>，类型为int</p></li><li><p>添加属性和注解，初始值为0</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@TableLogic</span></span><br><span class="line"><span class="meta">@TableField(fill = FieldFill.INSERT)</span></span><br><span class="line"><span class="keyword">private</span> Integer deleted;</span><br></pre></td></tr></table></figure></li><li><p>此时删除后，deleted会变为1</p></li></ul></li></ul><h2 id="复杂查询"><a href="#复杂查询" class="headerlink" title="复杂查询"></a>复杂查询</h2><ul><li><p>删除年龄大于等于12的</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testQuery</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    QueryWrapper&lt;User&gt; queryWrapper = <span class="keyword">new</span> QueryWrapper&lt;&gt;();</span><br><span class="line">    <span class="comment">//greater&amp;&amp;equals,查询年龄大于等于12岁的数据</span></span><br><span class="line">    queryWrapper.ge(<span class="string">&quot;age&quot;</span>, <span class="number">12</span>);</span><br><span class="line">    System.out.println(queryWrapper);</span><br><span class="line">    <span class="keyword">int</span> result = userMapper.delete(queryWrapper);</span><br><span class="line">    System.out.println(<span class="string">&quot;delete return count = &quot;</span> + result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>查询名为“sandy”的数据</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelectOne</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    QueryWrapper&lt;User&gt;queryWrapper = <span class="keyword">new</span> QueryWrapper&lt;&gt;();</span><br><span class="line">    queryWrapper.eq(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;Sandy&quot;</span>);</span><br><span class="line">    User user = userMapper.selectOne(queryWrapper);<span class="comment">//只能返回一条记录，多余一条则抛出异常</span></span><br><span class="line">    System.out.println(user);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>between使用</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelectCount</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    QueryWrapper&lt;User&gt;queryWrapper = newQueryWrapper&lt;&gt;();</span><br><span class="line">    queryWrapper.between(<span class="string">&quot;age&quot;</span>, <span class="number">20</span>, <span class="number">30</span>);</span><br><span class="line">    Integer count = userMapper.selectCount(queryWrapper); <span class="comment">//返回数据数量</span></span><br><span class="line">    System.out.println(count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>like的使用</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelectMaps</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    QueryWrapper&lt;User&gt;queryWrapper = <span class="keyword">new</span> QueryWrapper&lt;&gt;();</span><br><span class="line">    queryWrapper.like(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;e&quot;</span>).likeRight(<span class="string">&quot;email&quot;</span>, <span class="string">&quot;5&quot;</span>);</span><br><span class="line">    List&lt;User&gt; users = userMapper.selectList(queryWrapper);<span class="comment">//返回值是Map列表</span></span><br><span class="line">    System.out.println(users);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>orderby的使用</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">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSelectListOrderBy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    QueryWrapper&lt;User&gt;queryWrapper = <span class="keyword">new</span> QueryWrapper&lt;&gt;();</span><br><span class="line">    <span class="comment">//按年龄降序</span></span><br><span class="line">    queryWrapper.orderByDesc(<span class="string">&quot;age&quot;</span>);</span><br><span class="line">    List&lt;User&gt;users = userMapper.selectList(queryWrapper);</span><br><span class="line">    users.forEach(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    
    <summary type="html">MyBatisPlus是在MyBatis的基础上进行增强的框架，本文将记录一些重点知识，有助于读者快速入门。</summary>
    
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/categories/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
    
    <category term="后端工具/框架" scheme="https://nuyoah-xlh.github.io/tags/%E5%90%8E%E7%AB%AF%E5%B7%A5%E5%85%B7-%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>浅尝JVM</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/07/%E6%B5%85%E5%B0%9DJVM/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/07/%E6%B5%85%E5%B0%9DJVM/</id>
    <published>2022-01-07T06:22:54.353Z</published>
    <updated>2022-01-07T13:50:58.397Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="JVM的位置"><a href="#JVM的位置" class="headerlink" title="JVM的位置"></a>JVM的位置</h2><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_14-33-53.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><h2 id="JVM体系结构"><a href="#JVM体系结构" class="headerlink" title="JVM体系结构"></a>JVM体系结构</h2><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_14-41-16.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><h2 id="类加载器"><a href="#类加载器" class="headerlink" title="类加载器"></a>类加载器</h2><p><strong>作用：</strong>加载class文件。new Student()时，引用放在栈中，而实例放在堆中。</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_14-51-53.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><p><strong>过程（双亲委派机制 ）：</strong></p><ul><li>类加载器收到类加载的请求；</li><li>将这个请求向上委托给父类加载器去完成，一直向上委托，直到启动类加载器；</li><li>启动类加载器检查是否能加载当前类，如果能，结束；如果不能，则抛出异常，通知子类加载器加载；</li><li>重复步骤三，直到结束。</li></ul><p><strong>加载器：（上方是下方的父类）</strong></p><ul><li>启动类（根）加载器</li><li>扩展类加载器</li><li>应用程序加载器</li><li>自定义类加载器</li></ul><p><strong>注：native修饰的方法为调用本地方法栈，意为Java无法处理，调用C++方法-本地方法。</strong></p><h2 id="沙箱安全机制"><a href="#沙箱安全机制" class="headerlink" title="沙箱安全机制"></a>沙箱安全机制</h2><p>​    Java安全模型的核心就是Java沙箱（sandbox），什么是沙箱？沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中，并且严格限制代码对本地系统资源访问，通过这样的措施来保证对代码的有效隔离，防止对本地系统造成破坏。沙箱<strong>主要限制系统资源访问</strong>，那系统资源包括什么？——<code>CPU、内存、文件系统、网络</code>。不同级别的沙箱对这些资源访问的限制也可以不一样。</p><p>​    所有的Java程序运行都可以指定沙箱，可以定制安全策略。</p><h2 id="Native-amp-amp-方法区"><a href="#Native-amp-amp-方法区" class="headerlink" title="Native&amp;&amp;方法区"></a>Native&amp;&amp;方法区</h2><ul><li>凡是带了native的关键字的，说明java的作用范围达不到了，回去调用底层c/c++语言的库。</li><li>会进入本地方法栈，调用本地方法JNI</li><li>JNI：扩展java的使用，融合不同的编程语言为java所用</li><li>在内存区域中，专门开辟了一块内存区域：native method stack，用来登记native方法</li><li>在最终执行的时候，加载本地方法库中的方法调用JNI</li><li><strong>静态变量（static）、常量(final)、类信息(Class)、运行时常量(常量池)存在方法区，但实例变量存在堆内存中</strong></li></ul><h2 id="堆"><a href="#堆" class="headerlink" title="堆"></a>堆</h2><ul><li>一个jvm只有一个堆内存，大小可调节</li><li>细分三个区域：<ul><li>新生区（伊甸园区）</li><li>养老区</li><li>永久区（元空间）</li></ul></li><li>GC垃圾回收主要在前两个区</li><li>OOM：堆内存不够</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_20-39-54.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><h3 id="新生区"><a href="#新生区" class="headerlink" title="新生区"></a>新生区</h3><ul><li>类：诞生和成长、甚至死亡的地方；</li><li>伊甸园：所有的对象都是在这里new出来的；</li><li>幸存者区（0,1），暂时还未淘汰</li><li>使用的是浅gc</li></ul><h3 id="养老区"><a href="#养老区" class="headerlink" title="养老区"></a>养老区</h3><ul><li>多次淘汰后仍存在，则放到养老区</li><li>使用的是重gc</li></ul><h3 id="永久区（元空间）"><a href="#永久区（元空间）" class="headerlink" title="永久区（元空间）"></a>永久区（元空间）</h3><ul><li>常量池在元空间；</li><li>常驻内存，存放jdk自身的Class对象，interface元数据；</li><li>此区域不存在垃圾回收</li><li>在堆中，逻辑上存在，物理上不存在，又称“非堆”</li></ul><h3 id="OOM"><a href="#OOM" class="headerlink" title="OOM"></a>OOM</h3><ul><li>分析OOM原因的工具：JProfiler</li></ul><p>vm-options:</p><ul><li>-Xms：设置初始内存分配大小</li><li>-Xms：设置最大可分配内存</li><li>-XX:+PrintGCDetails：打印GC垃圾回收信息</li><li>-XX:+HeapDumpOnOutOfMemoryError：当抛出OutOfMemoryError异常时，产生dump文件，OutOfMemoryError可修改</li><li>例：<code>-Xms1m -Xms8m -XX:+HeapDumpOnOutOfMemoryError</code></li></ul><h3 id="GC算法"><a href="#GC算法" class="headerlink" title="GC算法"></a>GC算法</h3><h4 id="引用计数法"><a href="#引用计数法" class="headerlink" title="引用计数法"></a>引用计数法</h4><ul><li>计算每个对象的引用次数以决定GC</li></ul><h4 id="复制算法"><a href="#复制算法" class="headerlink" title="复制算法"></a>复制算法</h4><ul><li>两个幸存区，一个为from区，一个为to区，哪个为空则哪个为to区。from和to对象复制交换，以便每次gc，将Eden区幸存的对象放到空的to区中，同时from的对象也放到to区中</li><li>当一个对象经历了15次gc仍存活，则放到老年区<ul><li>-XX:MaxTenuringThreshold=15</li></ul></li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_21-24-47.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><h4 id="标记压缩清除算法（结合可达性算法）"><a href="#标记压缩清除算法（结合可达性算法）" class="headerlink" title="标记压缩清除算法（结合可达性算法）"></a>标记压缩清除算法（结合可达性算法）</h4><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_21-27-30.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><ul><li>缺点：两次扫描，浪费时间，会产生内存碎片</li><li>优点：不需要额外内存空间</li></ul><h4 id="标记压缩算法"><a href="#标记压缩算法" class="headerlink" title="标记压缩算法"></a>标记压缩算法</h4><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-07_21-30-24.jpg" alt="Snipaste_2021-07-26_18-52-23.jpg"></p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>内存效率：复制算法-&gt;标记清除算法-&gt;标记压缩算法（时间复杂度）</p><p>内存整齐度：复制算法=标记压缩算法-&gt;标记清除算法</p><p>内存利用率：标记压缩算法=标记清除算法-&gt;复制算法</p><ul><li>分代收集算法<ul><li>年轻代：<ul><li>存活率低</li><li>复制算法</li></ul></li><li>老年代：<ul><li>区域大、存活率高</li><li>标记清除+标记压缩混合</li></ul></li></ul></li></ul>]]></content>
    
    
    <summary type="html">本文将浅要地记录JVM的重点知识，以供交流学习。</summary>
    
    
    
    <category term="Java" scheme="https://nuyoah-xlh.github.io/categories/Java/"/>
    
    
    <category term="Java" scheme="https://nuyoah-xlh.github.io/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>Java基础-重点篇</title>
    <link href="https://nuyoah-xlh.github.io/2022/01/06/Java%E5%9F%BA%E7%A1%80-%E9%87%8D%E7%82%B9%E7%AF%87/"/>
    <id>https://nuyoah-xlh.github.io/2022/01/06/Java%E5%9F%BA%E7%A1%80-%E9%87%8D%E7%82%B9%E7%AF%87/</id>
    <published>2022-01-06T07:11:15.795Z</published>
    <updated>2022-01-07T13:49:59.084Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><h2 id="Java-两种核心机制"><a href="#Java-两种核心机制" class="headerlink" title="Java 两种核心机制"></a>Java 两种核心机制</h2><ul><li>Java 虚拟机 (Java Virtal Machine)</li><li>垃圾收集机制 (Garbage Collection)</li></ul><h3 id="核心机制-Java-虚拟机"><a href="#核心机制-Java-虚拟机" class="headerlink" title="核心机制-Java 虚拟机"></a>核心机制-Java 虚拟机</h3><ul><li>JVM 是一个虚拟的计算机，具有指令集并使用不同的存储区域。负责执行指<br>令，管理数据、内存、寄存器 。</li><li>对于不同的平台，有不同的虚拟机。只有某平台提供了对应的 java 虚拟机， java 程序才可在此平台运行</li><li>Java 虚拟机机制屏蔽了底层运行平台的差别，实现了一次编译，到处运行”</li></ul><h3 id="核心机制-垃圾回收"><a href="#核心机制-垃圾回收" class="headerlink" title="核心机制-垃圾回收"></a>核心机制-垃圾回收</h3><ul><li>不再使用的内存空间应回收垃圾回收。</li><li>垃圾回收在 Java 程序运行过程中自动进行，程序员无法精确控制和干预。</li></ul><h2 id="JDK和JRE"><a href="#JDK和JRE" class="headerlink" title="JDK和JRE"></a>JDK和JRE</h2><h3 id="JDK（Java开发工具包）"><a href="#JDK（Java开发工具包）" class="headerlink" title="JDK（Java开发工具包）"></a>JDK（Java开发工具包）</h3><p>​    JDK是提供给 Java 开发人员使用的，其中包含了 java 的开发工具，也包括了JRE 。所以安装了 JDK ，就不用在单独安装 JRE 了。<br>其中的开发工具：编译工具 (javac.exe) 打包工具 (jar)等。</p><h3 id="JRE-Java运行环境"><a href="#JRE-Java运行环境" class="headerlink" title="JRE(Java运行环境)"></a>JRE(Java运行环境)</h3><p>​    包括Java 虚拟机 (JVM Java Virtual Machine) 和 Java 程序所需的核心类库等，如果想要运行 一个开发好的 Java 程序，计算机中只需要安装 JRE 即可。</p><h2 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h2><p>Java 程序在执行过程中所发生的异常事件可分为两类：</p><ul><li>Error：Java 虚拟机无法解决的严重问题 。 如： JVM 系统内部错误 、 资源耗尽等严重情况 。 比如：StackOverflowError 和 OOM一般 不编写针对性的代码进行处理。</li><li>Exception 其它因编程错误或偶然的外在因素导致的一般性问题可以使用针对性的代码进行处理 。 例如：<ul><li>空指针访问</li><li>试图读取不存在的文件</li><li>网络连接中断</li><li>数组角标越界</li></ul></li></ul><h3 id="运行时异常"><a href="#运行时异常" class="headerlink" title="运行时异常"></a>运行时异常</h3><p>​    是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误，是程序员应该积极避免其出现的异常。</p><h3 id="编译时异常"><a href="#编译时异常" class="headerlink" title="编译时异常"></a>编译时异常</h3><p>​    是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。 编译器 要求 Java 程序必须捕获或声明所有编译时异常。</p><h3 id="异常处理机制"><a href="#异常处理机制" class="headerlink" title="异常处理机制"></a>异常处理机制</h3><h4 id="机制一"><a href="#机制一" class="headerlink" title="机制一"></a>机制一</h4><p>​    try-catch-finally</p><h4 id="机制二"><a href="#机制二" class="headerlink" title="机制二"></a>机制二</h4><p>​    throws语句，在方法声明中用 throws 语句可以声明抛出异常的列表 throws 后面的异常类型可以是方法中产生的异常类型也可以是它的父类。</p><h4 id="手动抛出异常"><a href="#手动抛出异常" class="headerlink" title="手动抛出异常"></a>手动抛出异常</h4><ul><li><p>首先要生成异常类对象 然后通过 throw 语句实现抛出操作 提交给 Java 运行环境；</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">IOException e=<span class="keyword">new</span> IOException()</span><br><span class="line"><span class="keyword">throw</span> e</span><br></pre></td></tr></table></figure></li><li><p>可以抛出的异常必须是 Throwable 或其子类的实例。</p></li></ul><h3 id="自定义异常类"><a href="#自定义异常类" class="headerlink" title="自定义异常类"></a>自定义异常类</h3><p>​    用户自定义异常类MyException ，用于描述数据取值范围错误信息。用户自己的异常类必须继承现有的异常类。</p><h2 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h2><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_17-22-12.jpg"></p><p><strong>并行：</strong>多 个 CPU 同时执行多个任务。比如：多个人同时做不同的事；</p><p><strong>并发：</strong>一 个 CPU( 采用时间片 同时执行多个任务。比如：秒杀、多个人做同一件事。</p><h3 id="线程的创建和启动"><a href="#线程的创建和启动" class="headerlink" title="线程的创建和启动"></a>线程的创建和启动</h3><p>Java 语言的 JVM 允许程序运行多个线程，它通过 java.lang.Thread类来体现。</p><h4 id="Thread类"><a href="#Thread类" class="headerlink" title="Thread类"></a>Thread类</h4><h5 id="构造器"><a href="#构造器" class="headerlink" title="构造器"></a>构造器</h5><ul><li>Thread()： 创建新的 Thread 对象</li><li>Thread(String threadname)： 创建线程并指定线程实例名</li><li>Thread( Runnable target) ：指定创建线程的目标对象，它实现了 Runnable 接口中的 run 方法；</li><li>Thread(Runnable target, String name)： 创建新的 Thread 对象</li></ul><h4 id="API中创建线程的两种方式"><a href="#API中创建线程的两种方式" class="headerlink" title="API中创建线程的两种方式"></a>API中创建线程的两种方式</h4><h5 id="方式一：-继承-Thread-类"><a href="#方式一：-继承-Thread-类" class="headerlink" title="方式一： 继承 Thread 类"></a>方式一： 继承 Thread 类</h5><ul><li>定义子类继承 Thread 类。</li><li>子类中重写 Thread 类中的 run 方法。</li><li>创建 Thread 子类对象，即创建了线程对象。</li><li>调用线程对象 start 方法：启动线程，调用 run 方法 。</li></ul><p><strong>注意：</strong>想要启动多线程，必须调用 start 方法 。手动调用run（）不是多线程；且一个线程对象只能启动一次。</p><h5 id="方式二：实现-Runnable-接口"><a href="#方式二：实现-Runnable-接口" class="headerlink" title="方式二：实现 Runnable 接口"></a>方式二：实现 Runnable 接口</h5><ul><li>定义子类 ，实现 Runnable 接口。</li><li>子类中重写 Runnable 接口中的 run 方法。</li><li>通过 Thread 类含参构造器创建线程对象。</li><li>将 Runnable 接口的子类对象作为实际参数 传递给 Thread 类的构造器中 。</li><li>调用 Thread 类的 start 方法：开启线程，调用 Runnable 子类接口的 run 方法。</li></ul><h5 id="对比"><a href="#对比" class="headerlink" title="对比"></a>对比</h5><ul><li>区别：<ul><li>继承Thread：线程代码存放 Thread 子类 run 方法中。</li><li>实现 Runnable ：线程代码存在接口的子类的 run 方法。</li></ul></li><li>实现 Runnable的好处：<ul><li>避免 了单继承的局限性多个线程可以共享同一个 接口实现类 的对象，非常适合多个相同线程来处理同一份资源。</li></ul></li></ul><h4 id="相关方法"><a href="#相关方法" class="headerlink" title="相关方法"></a>相关方法</h4><ul><li>void start(): 启动线程，并执行对象的 run() 方法；</li><li>run(): 线程在被调度时执行的操作；</li><li>String getName(): 返回线程的名称；</li><li>void setName(String name) :设置该线程名称；</li><li>static Thread currentThread (): 返回 当前线程 。在 Thread 子类中就是 this ，通常用于主线程和 Runnable 实现类。</li><li>static void yield() ：线程让步<ul><li>暂停当前正在执行的线程，把执行机会让给优先级相同或更高的线程</li><li>若队列中没有同优先级的线程，忽略此方法</li></ul></li><li>join() ：当某个程序执行流中调用其他线程的 join() 方法时调用线程将被阻塞，直到 join() 方法加入的 join 线程执行完为止；<ul><li>低优先级的线程也可以获得执行</li></ul></li><li>static void sleep(long millis): 指定时间-毫秒<ul><li>令当前活动线程在指定时间段内放弃对 CPU 控制 使其他线程有机会被执行时间到后重排队。</li></ul></li><li>stop(): 强制线程生命期结束，不推荐使用；</li><li>boolean isAlive()： 返回 boolean ，判断线程是否还活着。</li></ul><h3 id="线程的调度"><a href="#线程的调度" class="headerlink" title="线程的调度"></a>线程的调度</h3><ul><li>同优先级线程组成先进先出队列（先到先服务），使用时间片策略；</li><li>对高优先级，使用优先调度的抢占式策略；</li></ul><h4 id="线程的优先级等级"><a href="#线程的优先级等级" class="headerlink" title="线程的优先级等级"></a>线程的优先级等级</h4><ul><li>MAX_PRIORITY：10</li><li>MIN_PRIORITY： 1</li><li>NORM_PRIORITY ：5</li><li>getPriority()： 返回线程优先值；</li><li>setPriority(int newPriority ) 改变线程的优先级;</li></ul><p><strong>说明：</strong>线程创建时继承父线程的优先级，低优先级只是获得调度的概率低，并非一定是在高优先级线程之后才被调用。</p><h3 id="声明周期"><a href="#声明周期" class="headerlink" title="声明周期"></a>声明周期</h3><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_20-39-52.jpg"></p><h3 id="同步机制"><a href="#同步机制" class="headerlink" title="同步机制"></a>同步机制</h3><h4 id="同步代码块"><a href="#同步代码块" class="headerlink" title="同步代码块"></a>同步代码块</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(对象)&#123;</span><br><span class="line"><span class="comment">// 需要被同步的代码；</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="同步方法"><a href="#同步方法" class="headerlink" title="同步方法"></a>同步方法</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">show</span> <span class="params">(String name)</span></span>&#123;</span><br><span class="line"><span class="comment">// </span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>注意：</strong>必须确保使用同一个资源的多个线程共用一把锁，这个非常重要，否则就无法保证共享资源的安全。</p><h4 id="释放锁"><a href="#释放锁" class="headerlink" title="释放锁"></a>释放锁</h4><ul><li>当前线程的同步方法、同步代码块执行结束。</li><li>当前线程在同步代码块、同步方法中遇到 break 、 return 终止了该代码块、该方法的继续执行。</li><li>当前线程在同步代码块、同步方法中出现了未处理的 Error 或 Exception 导致异常结束。</li><li>当前线程在同步代码块、同步方法中执行了线程对象的 wait() 方法，当前线程暂停，并释放锁。</li></ul><h4 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h4><ul><li>不同的线程分别占用对方需要的同步资源不放弃，都在等待对方放弃自己需要的同步资源，就形成了线程的死锁；</li><li>出现死锁后，不会出现异常，不会出现提示，只是所有的线程都处于阻塞状态，无法继续；</li></ul><h4 id="Lock-锁"><a href="#Lock-锁" class="headerlink" title="Lock(锁)"></a>Lock(锁)</h4><p>ReentrantLock 类实现了 Lock ，它拥有与 synchronized 相同的并发性和内存语义， 在实现线程安全的控制中，比较常用的是ReentrantLock 可以显式加锁、释放锁 。</p><ul><li>使用 Lock 锁， JVM 将花费较少的时间来调度线程，性能更好。并且具有更好的扩展性（提供更多的子类）;</li></ul><h4 id="线程通信"><a href="#线程通信" class="headerlink" title="线程通信"></a>线程通信</h4><ul><li><p>wait()：令当前线程挂起并放弃 CPU 、 同步资源并等待，使别的线程可访问并修改共享资源，而当前线程 排队 等候其他线程调用notify() 或 notifyAll() 方法唤醒，唤醒后等待重新获得对监视器的所有权后才能继续执行。</p></li><li><p>notify()：唤醒正在排队等待同步资源的线程中优先级最高者结束等待；</p></li><li><p>notifyAll()：唤醒正在排队等待资源的所有线程结束等待；</p><p>这三个方法只有在 synchronized 方法或 synchronized 代码块中才能使用，否则会报异常。</p></li></ul><h2 id="Java常用类"><a href="#Java常用类" class="headerlink" title="Java常用类"></a>Java常用类</h2><h3 id="字符串相关"><a href="#字符串相关" class="headerlink" title="字符串相关"></a>字符串相关</h3><ul><li>String类：代表字符串。 Java 程序中的所有字符串字面值（如 “abc” ）都作为此类的实例实现。<ul><li>String 是一个 final 类，代表不可变的字符序列；</li><li>字符串常量存储在字符串常量池，目的是共享；字符串非常量对象存储在堆中</li><li>常用方法：<ul><li>int length() 返回字符串的长度；</li><li>char charAt(int index) 返回某索引处的字符；</li><li>boolean isEmpty() 判断是否是空字符串；</li><li>String toLowerCase() 使用默认语言环境 将 String 中的所有字符转换为小写</li><li>String toUpperCase() 使用默认语言环境 将 String 中的所有字符转换为大写</li><li>String trim() 返回字符串的副本 忽略前导空白和尾部空白；</li><li>boolean equals(Object obj) 比较字符串的内容是否相同；</li><li>String substring(int beginIndex, int endIndex) 返回一个新字符串 它是此字符串从 beginIndex 开始截取到 endIndex( 不包含）的一个子字符串 。</li><li>int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引；</li><li>int lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引；</li><li>boolean contains(CharSequence s) 当且仅当此字符串包含指定的 char 值序列时，返回 true</li><li>String replace(CharSequence target, CharSequence replacement) 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串、</li><li>String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串 。</li></ul></li><li>字符串-&gt;基本数据类型、包装类<ul><li>int parseInt (String s)</li></ul></li><li>基本 数据类型、包装类-&gt;字符串<ul><li>public String valueOf int n) </li></ul></li></ul></li><li>StringBuffer类：可变字符序列、效率低、线程安全<ul><li>StringBuffer append ( xxx)：提供了很多的 append() 方法 用于进行字符串拼接</li><li>StringBuffer delete (int start,int end)：删除指定位置的内容</li><li>StringBuffer replace (int start, int end, String str)str)：把 [start，end) 位置替换为 str</li><li>StringBuffer insert (int offset, xxx)xxx)：在指定位置插入 xxx</li><li>StringBuffer reverse ()：把当前字符序列逆转</li></ul></li><li>StringBuilder类：可变字符序列、效率高、 线程不安全</li></ul><h3 id="日期"><a href="#日期" class="headerlink" title="日期"></a>日期</h3><h4 id="java-util-Date-类"><a href="#java-util-Date-类" class="headerlink" title="java.util.Date 类"></a>java.util.Date 类</h4><p>​    表示特定的瞬间，精确到毫秒，过时。</p><h4 id="java-text-SimpleDateFormat类"><a href="#java-text-SimpleDateFormat类" class="headerlink" title="java.text.SimpleDateFormat类"></a>java.text.SimpleDateFormat类</h4><ul><li>SimpleDateFormat () ：默认的模式和语言环境创建对象</li><li>public SimpleDateFormat (String  pattern)：该构造方法可以用参数指定的格式创建一个对象</li><li>public Date parse(String source) 从给定字符串的开始解析文本，以生成一个日期。</li></ul><h3 id="Java比较器"><a href="#Java比较器" class="headerlink" title="Java比较器"></a>Java比较器</h3><ul><li>自然排序： java.lang.Comparable</li><li>定制排序： java.util.Comparator</li></ul><h3 id="Math-类"><a href="#Math-类" class="headerlink" title="Math 类"></a>Math 类</h3><ul><li>abs:绝对值</li><li>sqrt:平方根</li><li>pow(double a,doble b) : a的 b 次幂</li><li>max(double a,double b):最大值</li></ul><h3 id="BigInteger-类"><a href="#BigInteger-类" class="headerlink" title="BigInteger 类"></a>BigInteger 类</h3><ul><li>BigInteger 可以表示不可变的任意精度的整数</li><li>BigInteger (String val) : 根据字符串构建 BigInteger 对象</li><li>BigInteger add (BigInteger val) ：返回其值为 (this + val) 的 BigInteger</li><li>BigInteger subtract (BigInteger val) ：返回其值为 (this val) 的 BigInteger</li><li>BigInteger multiply (BigInteger val) ：返回其值为 (this * val) 的 BigInteger</li><li>BigInteger divide (BigInteger val) ：返回其值为 (this / val) 的 BigInteger 。整数相除只保留整数部分 。</li><li>BigInteger remainder (BigInteger val) ：返回其值为 (this % val) 的 BigInteger</li><li>BigInteger pow (int exponent) ：返回其值为 (this^exponent ) 的 BigInteger 。</li></ul><h3 id="java-math-BigDecimal-类"><a href="#java-math-BigDecimal-类" class="headerlink" title="java.math.BigDecimal 类"></a>java.math.BigDecimal 类</h3><ul><li>支持数字精度比较高</li><li>与BigInteger 方法相似</li></ul><h2 id="枚举类"><a href="#枚举类" class="headerlink" title="枚举类"></a>枚举类</h2><ul><li>枚举类对象的属性不应允许被改动 , 所以应该使用 private final 修饰</li><li>使用 enum 定义的枚举类 默认继承 了 java.lang.Enum 类，因此不能再继承其他类</li><li>枚举类的构造器只能使用 private 权限修饰符</li><li>主要方法：<ul><li>values() 方法 ：返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。</li><li>valueOf (String str ))：可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是，会有运行时异常</li><li>toString()：返回当前枚举类对象常量的名称</li><li>框架 = 注解 + 反射 + 设计模式。</li></ul></li><li>注解：Annotation<ul><li>@author标明开发该类模块的作者 多个作者之间使用,分割</li><li>@param对方法中某参数的说明 如果没有参数就不能写</li><li>@return对方法返回值的说明 如果方法的返回值类型是 void 就不能写</li><li>Override: 限定重写父类方法 , 该注解只能用于方法</li></ul></li></ul><h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><p>使用 Array 存储对象方面具有 一些弊端 ，而 Java 集合就像一种容器，可以动态地把多个对象的引用放入容器中。</p><p>两种体系：</p><ul><li>Collection 接口单列数据， 定义了存取一组对象的方法的集合<ul><li>List 元素有序、可重复的集合</li><li>Set 元素无序、不可重复的集合</li></ul></li><li>Map 接口： 双列数据，保存具有映射关系“ key-value 对”的集合</li></ul><h3 id="Collection接口方法："><a href="#Collection接口方法：" class="headerlink" title="Collection接口方法："></a>Collection接口方法：</h3><ul><li>add(Object obj)：添加</li><li>void clear()：清空集合；</li><li>boolean isEmpty():是否为空；</li><li>boolean contains(Object obj) 是通过元素的 equals 方法来判断是否是同一个对象；</li><li>boolean remove(Object obj) 通过 元素的 equals 方法判断是否是要删除的那个元素 。 只会删除找到的第一个元素</li><li>Object[] toArray()：转换为对象数组</li><li>iterator()：返回迭代器对象，用于集合遍历</li></ul><h3 id="Iterator接口的方法："><a href="#Iterator接口的方法：" class="headerlink" title="Iterator接口的方法："></a>Iterator接口的方法：</h3><ul><li>hasNext():boolean</li><li>next()</li><li>remove()</li><li>在调用it.next 方法之前必须要调用 it.hasNext 进行检测。若不调用，且下一条记录无效，直接调用 it.next 会抛出NoSuchElementException 异常。</li><li>Iterator 可以删除集合的元素 但是是遍历过程中通过迭代器对象的 remove 方法不是集合对象的 remove 方法</li></ul><h3 id="List接口方法"><a href="#List接口方法" class="headerlink" title="List接口方法"></a>List接口方法</h3><ul><li>void add( int index, Object ele 在 index 位置插入 ele 元素</li><li>Object get( int index): 获取指定 index 位置的元素</li><li>Object remove( int index): 移除指定 index 位置的元素，并返回此元素</li><li>Object set( int index, Object ele 设置指定 index 位置的元素为 ele</li><li>ArrayList:本质上， ArrayList 是对象引用的 一个 变长数组</li><li>LinkedList:双向链表,对频繁的插入或删除元素 的操作，建议使用 LinkedList 类，效率较高<ul><li>void addFirst (Object obj)</li><li>Object getFirst()</li><li>Object removeFirst()</li></ul></li><li>Vector:Vector 是线程安全的,慢，尽量不使用</li></ul><h4 id="面试题"><a href="#面试题" class="headerlink" title="面试题"></a>面试题</h4><p><strong>ArrayList 和 LinkedList 的 异同？</strong></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">二者都线程不安全，相对线程安全的Vector ，执行效率高。</span><br><span class="line">此外，ArrayList 是实现了基于动态数组的数据结构， LinkedList 基于链表的数据结构。对于随机访问 get 和 set ArrayList 觉得优于 LinkedList ，因为 LinkedList 要移动指针。对于新增和删除 操作 add( 特指插入 和 remove LinkedList 比较占优势，因为 ArrayList 要移动数据。</span><br></pre></td></tr></table></figure><p><strong>ArrayList 和 Vector 的区别？</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Vector 和 ArrayList 几乎是完全相同的 唯一的区别在于 Vector 是同步类 ( synchronized)，属于强同步类。因此开销就比 ArrayList 要大，访问要慢。正常情况下 大多数的 Java 程序员使用ArrayList 而不是 Vector, 因为同步完全可以由程序员自己来控制。 Vector 每次扩容请求其大小的 2 倍空间，而 ArrayList 是 1.5 倍。 Vector 还有一个子类 Stack 。</span><br></pre></td></tr></table></figure><ul><li>Set接口<ul><li>HashSet 是 Set 接口的典型实现，大多数时候使用 Set 集合时都使用这个实现类。</li><li>HashSet 不是线程安全的</li><li>对于存放在 Set 容器中的对象， 对应的类一定要重写 equals 和 hashCode(Object obj) 方法，以实现对象相等规则 。即： ：“相等的对象必须具有相等的散列码 。</li><li>LinkedHashSet:<ul><li>LinkedHashSet 是 HashSet 的子类</li><li>LinkedHashSet 插入性能略低于 HashSet 但在迭代访问 Set 里的全部元素时有很好的性能。</li></ul></li></ul></li></ul><h3 id="map接口"><a href="#map接口" class="headerlink" title="map接口"></a>map接口</h3><ul><li>Map 中的 key 用 Set 来存放， 不允许重复</li><li>其中， HashMap 是 Map 接口使用频率最高的实 类</li><li>Object put(Object key,Object value) value)：将指定 key-value 添加到 或修改 当前 map 对象中</li><li>Object remove(Object key) key)：移除指定 key 的 key-value 对，并返回 value</li><li>Object get(Object key) key)：获取指定 key 对应的 value</li><li>boolean containsKey(Object key) key)：是否包含指定的 key</li><li>int size()：返回 map 中 key-value 对的个数</li><li>HashMap 的内部存储结构其实是 数组和链表的结合</li><li>HashMap 数组扩容之后 最消耗性能的点就出现了：原数组中的数据必须重新计算其在新数组中的位置 并放进去这就是 resize 。<ul><li>如果我们已经预知 HashMap 中元素的个数那么预设元素的个数能够有效的提高 HashMap 的性能</li></ul></li><li>负载因子的大小决定了 HashMap 的数据密度。负载因子越大密度越大，发生碰撞的几率越高，数组中的链表越容易长<br>造成 查询或插入时的比较次数增多，性能会下降。</li></ul><h2 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h2><p>所谓泛型就是允许在定义类 、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型 。</p><ul><li>体会：使用泛型的主要优点是能够在编译时而不是在运行时检测错误。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_22-30-03.jpg"></p><ul><li>通配符？<ul><li>List&lt;?&gt;是 List<String> 、 List<Object> 等各种泛型 List 的父类。</li><li>读取 List&lt;?&gt; 的对象 list 中的元素时，永远是安全的，因为不管 list 的真实类型是什么，它包含的都是 Object</li><li>写入 list 中的元素时，不行。因为我们不知道 c 的元素类型，我们不能向其中添加对象。null例外）</li></ul></li></ul><h2 id="IO流"><a href="#IO流" class="headerlink" title="IO流"></a>IO流</h2><h3 id="File类的使用"><a href="#File类的使用" class="headerlink" title="File类的使用"></a>File类的使用</h3><p>java.io.File 类： 文件和文件目录路径的抽象表示形式，与平台无关</p><p>常用构造器：</p><ul><li>public File(String pathname）：以pathname 为路径创建 File 对象，可以是 绝对路径或者相对路径 </li><li>路径分隔符：<ul><li>windows 和 DOS 系统默认使用 “\”来表示</li><li>UNIX 和 URL 使用“/”来表示</li></ul></li><li>public String getAbsolutePath() 获取绝对路径</li><li>public String getParent() 获取上层文件目录路径 。 若无返回 null</li><li>public boolean createNewFile():创建文件 。 若 文件存在则不创建 返回 false</li><li>public boolean mkdirs （）创建文件目录 。 如果上层文件目录不存在一并创建创建文件 。 若文件存在,则不创建,返回 false</li><li>public boolean delete（） 删除 文件或者文件夹</li></ul><h3 id="文件流"><a href="#文件流" class="headerlink" title="文件流"></a>文件流</h3><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_22-41-01.jpg"></p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_22-41-45.jpg"></p><h3 id="缓冲流"><a href="#缓冲流" class="headerlink" title="缓冲流"></a>缓冲流</h3><p>​    向流中写入字节时，不会直接写到文件先写到缓冲区中，直到缓冲区写满BufferedOutputStream，才会把缓冲区中的数据一次性写到文件 里 。使用方法flush() 可以强制将缓冲区的内容全部写入输出流</p><h2 id="反射机制"><a href="#反射机制" class="headerlink" title="反射机制"></a>反射机制</h2><p>​    Reflection （反射）是 被视为动态语言的关键，反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息，并能直接操作任意对象的内部属性及方法 。</p><p>​    加载完类之后 在堆内存的方法区中就产生了一个 Class 类型的对象 一个类只有一个 Class 对象 这个对象就包含了完整的类的结构信息 。 我们可以通过这个对象看到类的结构 。 这个对象就像一面镜子 透过这个镜子看到类的结构 所以 我们形象的称之为：反射 。</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_22-51-42.jpg"></p><ul><li>java是静态语言，但可以使用反射机制等获得动态语言特性；</li></ul><h3 id="反射的应用：动态代理"><a href="#反射的应用：动态代理" class="headerlink" title="反射的应用：动态代理"></a>反射的应用：动态代理</h3><ul><li>使用一个代理将对象包装起来 , 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。</li><li>Proxy ：专门完成代理的操作类，是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2022-01-06_23-00-51.jpg"></p>]]></content>
    
    
    <summary type="html">Java基础-重点篇,记录Java重点知识</summary>
    
    
    
    <category term="Java" scheme="https://nuyoah-xlh.github.io/categories/Java/"/>
    
    
    <category term="Java" scheme="https://nuyoah-xlh.github.io/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>PR快速入门技巧</title>
    <link href="https://nuyoah-xlh.github.io/2021/10/10/PR%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/"/>
    <id>https://nuyoah-xlh.github.io/2021/10/10/PR%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/</id>
    <published>2021-10-10T07:56:19.648Z</published>
    <updated>2022-10-09T14:40:00.339Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><ul><li><p>开启</p><ul><li>新建项目后，可以新建左下角新建一个素材箱，在其中导入素材，并可以拖动某个素材到右下角进行编辑/查看。</li></ul></li><li><p>裁剪素材</p><ul><li>在工具栏找到【剃刀工具】，对素材切割，后可用【选择工具】进行删除等操作。</li><li>裁剪之后，可以在素材左边出现【红色中括号】后，向左拖动即可恢复原长度。</li></ul></li><li><p>拼接素材</p><ul><li>直接在素材中将素材拖到右边编辑区的素材尾部即可。</li></ul></li><li><p>处理声音</p><ul><li><p>将声音素材导入素材箱后，再拖到右边编辑区即可。对应左边的区域，选中【S】后可对该声音独奏，选中【M】可对该声音静音。</p></li><li><p>选中某些声音后，可点击左上方的音频剪辑混和器进行音量调节等操作。</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_15-59-25.jpg" alt="20201020210157514.jpg"></p></li><li><p>字幕</p><ul><li>【文件】-&gt;【新建】-&gt;【旧版标题】即可设置字幕，然后从素材中将字幕拖到编辑区。</li><li>alt+滚轮可对其进行缩放。</li></ul></li><li><p>视频重叠</p><ul><li>将一个视频素材放到另一个视频上方，双击右上角视频即可调节大小和位置。</li></ul></li><li><p>制作动态弹幕</p><ul><li>用上面的方法添加字幕的方法添加一定数量的文字，然后把弹幕素材拖到编辑区，单击弹幕素材找左上角【效果控件】-&gt;【运动】-&gt;【位置】（鼠标放到坐标旁边可以移动到初始位置），点击左边【小闹钟】再次拖动到最终位置。</li></ul></li><li><p>素材加速/减速</p><ul><li>选中编辑区的素材后，右击选择【速度/持续时间】，可进行某个素材的加速/减速。</li><li>对素材的某一小段进行变速时，可以先用【剃刀工具】进行切割，再选中进行上述变速操作。</li><li><strong>注意：</strong>对中间某素材减速时，可能会被后面的素材遮挡，所以要先把后面的素材往后拖，变速后再接上。</li></ul></li><li><p>视频过渡效果</p><ul><li>点击上方【效果】-&gt;【视频过渡/音频过渡】-&gt;拖到连接处即可。</li></ul></li><li><p>制作鬼畜等效果</p><ul><li>双击某素材进行预览，对某段素材标记【入点】和【出点】，再将大画面拖到编辑区即可。还可进行ctrl+c、ctrl+v进行复制粘贴。</li></ul></li><li><p>制作片尾字幕</p><ul><li>将片尾剪断，选中末尾片段，在左上角进行编辑，先在某位置点击【位置】、【缩放】左边的小闹钟，然后将右边进度条拖到另一位置，改变视频图像的大小和位置即可。然后使用【制作动态弹幕】的方法添加滚动字幕。</li></ul></li><li><p>去水印</p><ul><li>先将素材拖到编辑区</li><li>【素材框】-&gt;【新建项目】-&gt;【调整图层】，将其拖到编辑区</li><li>在【效果】处搜索【中间值】，将其拖到编辑区的调整图层上，然后选择左上方的【中间值】，选择一个样式调整，再调节【半径】，直到水印消失。</li></ul></li><li><p>导出</p><ul><li>点击【文件】-&gt;【导出】-&gt;【媒体】-&gt;【格式：H.264(即为MP4格式)】-&gt;勾选【导出视频】、【导出音频】，导出即可。</li></ul></li></ul><p>​    </p>]]></content>
    
    
    <summary type="html">10分钟让你快速入门PR，能够实现相对简单的PR需求。</summary>
    
    
    
    <category term="PR" scheme="https://nuyoah-xlh.github.io/categories/PR/"/>
    
    
    <category term="PR" scheme="https://nuyoah-xlh.github.io/tags/PR/"/>
    
  </entry>
  
  <entry>
    <title>PS快速入门技巧</title>
    <link href="https://nuyoah-xlh.github.io/2021/10/10/PS%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/"/>
    <id>https://nuyoah-xlh.github.io/2021/10/10/PS%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/</id>
    <published>2021-10-10T06:34:48.138Z</published>
    <updated>2022-10-09T14:40:04.546Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\css\APlayer.min.css"><script src="\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\js\Meting.min.js"></script><ul><li><p>置入嵌入对象</p><p>将图片放到另一张图片中</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_14-39-43.jpg" alt="20201020210157514.jpg"></p></li><li><p>新建的文档，可以用左边工具栏“前景色”，alt+delete改变背景色</p><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_14-41-20.jpg" alt="20201020210157514.jpg"></p></li><li><p>alt+鼠标滚轮可以放大缩小图片</p></li><li><p>插入文字后，用ctrl+鼠标左键进行调整角度和放大缩小</p></li><li><p>双击图层可以弹出图层样式设置</p></li><li><p>保存格式</p><ul><li>PSD格式：可保留痕迹，便于再次进行编辑</li><li>JPG格式：通用的图片格式</li><li>PNG格式：保留透明区域（jpg会自动填充白色)</li></ul></li><li><p>移动工具</p><ul><li>选择移动工具后，可调节上方的选项。其中，勾选<strong>自动选择</strong>后，可以灵活移动图层。勾选<strong>显示变换控件</strong>后，可以显示被移动的控件，且支持放大缩小，注意：<strong>直接缩放不会改变宽高比例，按住shift后再进行缩放可自由调节</strong>。</li><li>将鼠标移动到某个图层外面，按住不动可进行拖动旋转。</li><li>鼠标点击图层后，快捷键 ctrl+T可进行如上操作，尽量<strong>不开启“显示变换控件”</strong>。调节后双击图层确定。</li><li>组：ctrl+鼠标点击右边图层名称，选择多个图层作为一组，可进行同时移动、缩放等操作。选择多个图层后，点击下图图标可进行创建组。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_15-25-24.jpg" alt="20201020210157514.jpg"></p></li><li><p>图层复制/删除/新建</p><ul><li>复制快捷键：ctrl+j</li><li>删除快捷键：delete</li><li>选中图像移动/缩放：ctrl+t</li><li>新建图层：见右下角图标</li></ul><p><img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_15-26-55.jpg" alt="20201020210157514.jpg"></p></li><li><p>回退</p><ul><li>快捷键：ctrl+z</li></ul></li><li><p>对齐图层</p><ul><li>多选图层后，可以使用上方对齐功能</li></ul><p>  <img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_15-27-56.jpg" alt="20201020210157514.jpg"></p></li><li><p>色相</p><ul><li>选中图层后，点击图像-&gt;调整-&gt;色相/饱和度</li></ul></li><li><p>选区</p><ul><li>左边栏第二个矩形选框工具，用鼠标可以拖出矩形框，按照shift同时拖动鼠标可以画出正方形/圆形。</li><li>选区后可以对其进行单独调整。</li><li>选区后可右击选择“变换选区”进行调整</li><li>点击下图第二个图标可以实现多选。</li></ul><p>  <img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_15-29-25.jpg" alt="20201020210157514.jpg"></p><ul><li>椭圆形选框方法类似。</li><li>快捷键：<ul><li>多选几个选区：shift+画图</li><li>减选区：alt+画图</li></ul></li></ul></li><li><p>羽化 </p><ul><li>羽化后，边框可以更柔和，有一个虚化的效果 </li></ul><p>  <img src="https://cdn.jsdelivr.net/gh/Nuyoah-xlh/jsDelivr-CDN/img/article_pic/Snipaste_2021-10-10_15-31-24.jpg" alt="20201020210157514.jpg"></p></li><li><p>套索工具</p><ul><li>左边栏第三个工具图标，可以进行不规则选区。对选区可进行羽化</li><li>快捷键ctrl+T可以进行自由变换（旋转等操作)</li><li>其中的多变形套索工具可以画直线，点与点之间连线进行抠图。</li><li>磁性套索工具，可以智能识别形状并增加节点。</li><li>在使用磁性套索工具时可以按住alt键同时操作，可以在磁性和多边形套索中不断切换。</li></ul></li><li><p>抠完图后，可以使用移动工具直接将其拖到另一个打开的文件中进行拼接</p></li><li><p>快速选择工具</p><ul><li>左边工具栏第四个，按住alt+右键进行拖动，可改变圆的大小。可自动框选特定形状。<ul><li>左上方的菜单栏可选择增加选区或减少选区。</li><li>上方的【选择主体】，可以自动识别并对主体部分选区。</li><li>上方的【选择并遮住】，可以对选区的边缘进行处理。</li></ul></li></ul></li><li><p>魔棒工具     </p><ul><li>【容差】可以改变选区范围</li><li>可以和选择工具交替使用</li></ul></li><li><p>对头发抠图</p><ul><li>扣大致图像后-&gt;【选择并遮住】-&gt;左边栏【调整边缘画笔工具】-&gt;【净化颜色】/羽化/平滑</li></ul></li><li><p>裁剪工具</p><ul><li>可对照片进行裁剪，还可以设定进行1：2裁剪 </li></ul></li><li><p>图片拉伸后，选择上方【内容识别】可对周围自动识别填充</p></li><li><p>【切片工具】把照片切成几份。更精准方法：打开【视图】-&gt;【标尺】，把标尺拖出形成参考线，点击上方【基于参考线的切片】，然后点击【文件】-&gt;【导出】-&gt;【存储为Web所用格式】-&gt;【JPEG】格式-&gt;【存储为html和图像】，可以导出切片和一个html文件。超链接：对某一切片右击后选择【编辑切片选项】，将特定网址复制到URL上，再进行上述导出操作即可。</p></li><li><p>剪贴蒙版</p><ul><li>在空白上新建一个选区后，置入对象，对右边名称右击后选择剪贴蒙版。还可以输入文字后插入图片再剪贴蒙版。</li></ul></li><li><p>显示取样环</p><ul><li>可以显示出取样环，取色更加清楚。</li></ul></li><li><p>人物祛斑</p><ul><li>使用污点修复画笔工具快捷修复。</li><li>使用修补工具框选后拖到正常区域。</li><li>内容感知移动工具，可对某区域进行框选并移动，且修复原区域（调节上方的结构和颜色可以进行细节优化）。</li></ul></li><li><p>模糊工具组</p><ul><li>使图像模糊，看起来更光滑</li></ul></li><li><p>调色</p><ul><li>图像-&gt;调整-&gt;曲线</li><li>图像-&gt;调整-&gt;色彩平衡    //可以调节色彩</li></ul></li><li><p>仿制图章工具组</p><ul><li>按下alt同时点击鼠标右键可以调节圆圈大小</li><li>在某区域按下alt键同时点击鼠标左键即可选色，然后在另一个区域长按鼠标左键进行复制。</li><li>【硬度】调小后可以更加柔和。</li></ul></li></ul>]]></content>
    
    
    <summary type="html">10分钟让你快速入门PS，能够实现相对简单的ps需求。</summary>
    
    
    
    <category term="PS" scheme="https://nuyoah-xlh.github.io/categories/PS/"/>
    
    
    <category term="PS" scheme="https://nuyoah-xlh.github.io/tags/PS/"/>
    
  </entry>
  
</feed>
