<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>杨柳自留地</title>
  
  <subtitle>人生如逆旅，我亦是行人</subtitle>
  <link href="https://www.ripic.site/atom.xml" rel="self"/>
  
  <link href="https://www.ripic.site/"/>
  <updated>2023-10-19T09:28:53.444Z</updated>
  <id>https://www.ripic.site/</id>
  
  <author>
    <name>杨柳清风</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>DDD图示</title>
    <link href="https://www.ripic.site/archives/2023/03/07/ddd-image.html"/>
    <id>https://www.ripic.site/archives/2023/03/07/ddd-image.html</id>
    <published>2023-03-07T17:09:40.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<div class="tag-plugin image"><div class="image-bg"><img src="https://static.dev86.site/note-res/note/202303/2AEEDA9BC3D204E935062510226F57F5%20.png" fancybox="true"/></div></div>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;tag-plugin image&quot;&gt;&lt;div class=&quot;image-bg&quot;&gt;&lt;img src=&quot;https://static.dev86.site/note-res/note/202303/2AEEDA9BC3D204E935062510226F57F</summary>
      
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
  </entry>
  
  <entry>
    <title>职场趣闻</title>
    <link href="https://www.ripic.site/archives/2023/02/16/workplace-anecdotes.html"/>
    <id>https://www.ripic.site/archives/2023/02/16/workplace-anecdotes.html</id>
    <published>2023-02-16T11:13:15.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>最近在V站上刷到这样一则有趣的问题：</p><p><strong>如何让团队又能干，又不具有威胁性？ 准备用末尾淘汰策略如何</strong></p><p>里面有一个回答特别有趣，简单记录一下：</p><blockquote><p>俗话说有钱能使鬼推磨，所以你给他们涨薪，就能让他们干更多事。<br>俗话又说，饱暖思淫欲，所以你给他们涨薪，金钱就能腐蚀他们的心灵让他们不具威胁性。<br>俗话再说，挡人发财如杀人父母，所以千万别末尾淘汰，小心人报复。</p><p>以上。</p></blockquote><p>原文：<a href="https://v2ex.com/t/916355">https://v2ex.com/t/916355</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;最近在V站上刷到这样一则有趣的问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何让团队又能干，又不具有威胁性？ 准备用末尾淘汰策略如何&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;里面有一个回答特别有趣，简单记录一下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;俗话说有钱能使鬼推磨，所以你给他们</summary>
      
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
    <category term="职场" scheme="https://www.ripic.site/tags/%E8%81%8C%E5%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>java多线程（一）</title>
    <link href="https://www.ripic.site/archives/2023/01/29/java-Thread-1.html"/>
    <id>https://www.ripic.site/archives/2023/01/29/java-Thread-1.html</id>
    <published>2023-01-29T16:58:18.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>更新时间：2023年1月29日，本系列预计3篇文章，本篇文章更新60%<br>技术类文章欢迎勘误，勘误邮箱：report#ripic.site(#换@)</p></blockquote><p>启动一个新的java线程还是比较简单的，下面代码通过Lamda表达式描述了java线程的启动方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">Thread</span>(()-&gt;&#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">6</span>; i++) &#123;</span><br><span class="line">System.out.println(i);</span><br><span class="line">&#125;</span><br><span class="line">&#125;).start();</span><br></pre></td></tr></table></figure><p>Java的线程创建和启动非常简单，但如果问一个线程是怎么启动起来的往往并不清楚，甚至不知道为什么启动时是调用start()，而不是调用run()方法呢？</p><p>下面引用一张很经典的图片，来说明一个新的java线程被创建的过程：</p><div class="tag-plugin image"><div class="image-bg"><img src="https://static.dev86.site/note-res/note/202301/java-thread.png" fancybox="true"/></div></div><p>通过上面的图片，我们很清晰的知道：</p><ul><li>线程的启动会涉及到本地方法（JNI）的调用，也就是那部分 C++ 编写的代码。</li><li>JVM 的实现中会有不同操作系统对线程的统一处理，比如：Win、Linux、Unix。</li><li>线程的启动会涉及到线程的生命周期状态（RUNNABLE），以及唤醒操作，所以最终会有回调操作（也就是调用我们的 run() 方法）</li></ul><p>因此我们应该清楚，我们在程序运行的过程中只涉及到start()方法的调用，在Thread内部由程序调用run()方法启动线程。</p><p>下面，深入源码查看一下线程的启动过程</p><h1 id="start方法"><a href="#start方法" class="headerlink" title="start方法"></a>start方法</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// JDK 源码</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (threadStatus != <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalThreadStateException</span>();</span><br><span class="line"></span><br><span class="line">    group.add(<span class="built_in">this</span>);</span><br><span class="line">    <span class="type">boolean</span> <span class="variable">started</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        start0();</span><br><span class="line">        started = <span class="literal">true</span>;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!started) &#123;</span><br><span class="line">                group.threadStartFailed(<span class="built_in">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable ignore) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">start0</span><span class="params">()</span>;</span><br></pre></td></tr></table></figure><ul><li>首先，start()方法是一个synchronized方法，为了避免多次调用，会进行threadStatus!&#x3D;0的判断；</li><li>start0()在后续的源码中能够发现，是一个本地方法，与JVM虚拟机息息相关；</li><li>group.add(this)是把当前方法加入线程组。<br>从上面的代码可以看出start0()是新建县城的核心，下面我们继续探究</li></ul><h2 id="start0-本地方法"><a href="#start0-本地方法" class="headerlink" title="start0()本地方法"></a>start0()本地方法</h2><p>我们注意到，在<code>public class Thread implements Runnable&#123;&#125;</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">registerNatives</span><span class="params">()</span>;</span><br><span class="line"><span class="keyword">static</span> &#123;</span><br><span class="line">    registerNatives();</span><br><span class="line">    EMPTY_STACK_TRACE = <span class="keyword">new</span> <span class="title class_">StackTraceElement</span>[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个方法中调用了本地方法<code>registerNatives()</code>，我们先来探究这个方法的底层实现。</p><p>源码：<a href="https://github.com/openjdk/jdk/blob/master/src/java.base/share/native/libjava/Thread.c">https://github.com/openjdk/jdk/blob/master/src/java.base/share/native/libjava/Thread.c</a></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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="type">static</span> JNINativeMethod methods[] = &#123;</span><br><span class="line">    &#123;<span class="string">&quot;start0&quot;</span>,           <span class="string">&quot;()V&quot;</span>,        (<span class="type">void</span> *)&amp;JVM_StartThread&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;stop0&quot;</span>,            <span class="string">&quot;(&quot;</span> OBJ <span class="string">&quot;)V&quot;</span>, (<span class="type">void</span> *)&amp;JVM_StopThread&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;isAlive&quot;</span>,          <span class="string">&quot;()Z&quot;</span>,        (<span class="type">void</span> *)&amp;JVM_IsThreadAlive&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;suspend0&quot;</span>,         <span class="string">&quot;()V&quot;</span>,        (<span class="type">void</span> *)&amp;JVM_SuspendThread&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;resume0&quot;</span>,          <span class="string">&quot;()V&quot;</span>,        (<span class="type">void</span> *)&amp;JVM_ResumeThread&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;setPriority0&quot;</span>,     <span class="string">&quot;(I)V&quot;</span>,       (<span class="type">void</span> *)&amp;JVM_SetThreadPriority&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;yield&quot;</span>,            <span class="string">&quot;()V&quot;</span>,        (<span class="type">void</span> *)&amp;JVM_Yield&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;sleep&quot;</span>,            <span class="string">&quot;(J)V&quot;</span>,       (<span class="type">void</span> *)&amp;JVM_Sleep&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;currentThread&quot;</span>,    <span class="string">&quot;()&quot;</span> THD,     (<span class="type">void</span> *)&amp;JVM_CurrentThread&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;interrupt0&quot;</span>,       <span class="string">&quot;()V&quot;</span>,        (<span class="type">void</span> *)&amp;JVM_Interrupt&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;holdsLock&quot;</span>,        <span class="string">&quot;(&quot;</span> OBJ <span class="string">&quot;)Z&quot;</span>, (<span class="type">void</span> *)&amp;JVM_HoldsLock&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;getThreads&quot;</span>,        <span class="string">&quot;()[&quot;</span> THD,   (<span class="type">void</span> *)&amp;JVM_GetAllThreads&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;dumpThreads&quot;</span>,      <span class="string">&quot;([&quot;</span> THD <span class="string">&quot;)[[&quot;</span> STE, (<span class="type">void</span> *)&amp;JVM_DumpThreads&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;setNativeName&quot;</span>,    <span class="string">&quot;(&quot;</span> STR <span class="string">&quot;)V&quot;</span>, (<span class="type">void</span> *)&amp;JVM_SetNativeThreadName&#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>核心代码如上，主要是“注册”了一些核心的功能性方法，start0()调用的是<code>JVM_StartThread</code>，继续分析</p><h2 id="JVM-StartThread"><a href="#JVM-StartThread" class="headerlink" title="JVM_StartThread"></a>JVM_StartThread</h2><p>源码（2933行附近）：<a href="https://github.com/openjdk/jdk/blob/master/src/hotspot/share/prims/jvm.cpp">https://github.com/openjdk/jdk/blob/master/src/hotspot/share/prims/jvm.cpp</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">JVM_ENTRY</span>(<span class="type">void</span>, <span class="built_in">JVM_StartThread</span>(JNIEnv* env, jobject jthread))</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  JavaThread *native_thread = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">  <span class="type">bool</span> throw_illegal_thread_state = <span class="literal">false</span>;</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="function">MutexLocker <span class="title">mu</span><span class="params">(Threads_lock)</span></span>;</span><br><span class="line">    <span class="keyword">if</span> (java_lang_Thread::<span class="built_in">thread</span>(JNIHandles::<span class="built_in">resolve_non_null</span>(jthread)) != <span class="literal">NULL</span>) &#123;</span><br><span class="line">      throw_illegal_thread_state = <span class="literal">true</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      jlong size =</span><br><span class="line">             java_lang_Thread::<span class="built_in">stackSize</span>(JNIHandles::<span class="built_in">resolve_non_null</span>(jthread));</span><br><span class="line">      <span class="built_in">NOT_LP64</span>(<span class="keyword">if</span> (size &gt; SIZE_MAX) size = SIZE_MAX;)</span><br><span class="line">      <span class="type">size_t</span> sz = size &gt; <span class="number">0</span> ? (<span class="type">size_t</span>) size : <span class="number">0</span>;</span><br><span class="line">      native_thread = <span class="keyword">new</span> <span class="built_in">JavaThread</span>(&amp;thread_entry, sz); <span class="comment">//创建线程</span></span><br><span class="line">      <span class="keyword">if</span> (native_thread-&gt;<span class="built_in">osthread</span>() != <span class="literal">NULL</span>) &#123;</span><br><span class="line">        native_thread-&gt;<span class="built_in">prepare</span>(jthread);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">  Thread::<span class="built_in">start</span>(native_thread); <span class="comment">//启动线程</span></span><br><span class="line"></span><br><span class="line">JVM_END</span><br></pre></td></tr></table></figure><p>由于源码较多，仅保留了<code>创建线程</code>和<code>启动线程</code>的源码，更多源码，请前往Github查看</p><p>注意到在创建线程的时候用到了<code>thread_entry</code>，下面贴一下他的源码</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><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="function"><span class="type">static</span> <span class="type">void</span> <span class="title">thread_entry</span><span class="params">(JavaThread* thread, TRAPS)</span> </span>&#123;</span><br><span class="line">  <span class="function">HandleMark <span class="title">hm</span><span class="params">(THREAD)</span></span>;</span><br><span class="line">  <span class="function">Handle <span class="title">obj</span><span class="params">(THREAD, thread-&gt;threadObj())</span></span>;</span><br><span class="line">  <span class="function">JavaValue <span class="title">result</span><span class="params">(T_VOID)</span></span>;</span><br><span class="line">  JavaCalls::<span class="built_in">call_virtual</span>(&amp;result,</span><br><span class="line">                          obj,</span><br><span class="line">                          vmClasses::<span class="built_in">Thread_klass</span>(),</span><br><span class="line">                          vmSymbols::<span class="built_in">run_method_name</span>(),</span><br><span class="line">                          vmSymbols::<span class="built_in">void_method_signature</span>(),</span><br><span class="line">                          THREAD);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>根据方法名可以猜测，这个方法起到了<strong>线程入口</strong>的作用，这里面包含了线程会掉函数<code>call_virtual</code>，这个方法会回调JVM（通过这个方法调用JVM中的函数）。<br>回调中涉及到<code>vmSymbols</code>方法（源码：<a href="https://github.com/openjdk/jdk/blob/master/src/hotspot/share/classfile/vmSymbols.hpp#L400%EF%BC%89">https://github.com/openjdk/jdk/blob/master/src/hotspot/share/classfile/vmSymbols.hpp#L400）</a></p><figure class="highlight cpp"><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">#<span class="keyword">define</span> VM_SYMBOLS_DO(template, do_alias)</span></span><br><span class="line"><span class="built_in">template</span>(run_method_name, <span class="string">&quot;run&quot;</span>) </span><br></pre></td></tr></table></figure><p>这里就是调用java中的run()方法，现在整个调用过程逐渐清晰起来了。下面我们继续循着这个调用过程剖析调用过程。</p><h2 id="创建线程"><a href="#创建线程" class="headerlink" title="创建线程"></a>创建线程</h2><h3 id="JavaThread"><a href="#JavaThread" class="headerlink" title="JavaThread"></a>JavaThread</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">native_thread = <span class="keyword">new</span> <span class="built_in">JavaThread</span>(&amp;thread_entry, sz);</span><br></pre></td></tr></table></figure><p>源码：<a href="https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/javaThread.cpp#L592">https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/javaThread.cpp#L592</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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">JavaThread::<span class="built_in">JavaThread</span>(ThreadFunction entry_point, <span class="type">size_t</span> stack_sz) : <span class="built_in">JavaThread</span>() &#123;</span><br><span class="line">  _jni_attach_state = _not_attaching_via_jni;</span><br><span class="line">  <span class="built_in">set_entry_point</span>(entry_point);</span><br><span class="line">  <span class="comment">// Create the native thread itself.</span></span><br><span class="line">  <span class="comment">// %note runtime_23</span></span><br><span class="line">  os::ThreadType thr_type = os::java_thread;</span><br><span class="line">  thr_type = entry_point == &amp;CompilerThread::thread_entry ? os::compiler_thread :</span><br><span class="line">                                                            os::java_thread;</span><br><span class="line">  os::<span class="built_in">create_thread</span>(<span class="keyword">this</span>, thr_type, stack_sz);</span><br><span class="line">  <span class="comment">// The _osthread may be null here because we ran out of memory (too many threads active).</span></span><br><span class="line">  <span class="comment">// We need to throw and OutOfMemoryError - however we cannot do this here because the caller</span></span><br><span class="line">  <span class="comment">// may hold a lock and all locks must be unlocked before throwing the exception (throwing</span></span><br><span class="line">  <span class="comment">// the exception consists of creating the exception object &amp; initializing it, initialization</span></span><br><span class="line">  <span class="comment">// will leave the VM via a JavaCall and then all locks must be unlocked).</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// The thread is still suspended when we reach here. Thread must be explicit started</span></span><br><span class="line">  <span class="comment">// by creator! Furthermore, the thread must also explicitly be added to the Threads list</span></span><br><span class="line">  <span class="comment">// by calling Threads:add. The reason why this is not done here, is because the thread</span></span><br><span class="line">  <span class="comment">// object must be fully initialized (take a look at JVM_Start)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>ThreadFunction entry_point，就是我们上面的 thread_entry 方法。</li><li>size_t stack_sz，表示进程中已有的线程个数。这两个参数(thr_type,stack_sz)，都会传递给 os::create_thread 方法，用于创建线程使用。</li></ul><h3 id="os-create-thread"><a href="#os-create-thread" class="headerlink" title="os::create_thread"></a>os::create_thread</h3><p>这里以linux为例<br>源码：<a href="https://github.com/openjdk/jdk/blob/master/src/hotspot/os/linux/os_linux.cpp#L816">https://github.com/openjdk/jdk/blob/master/src/hotspot/os/linux/os_linux.cpp#L816</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">bool</span> <span class="title">os::create_thread</span><span class="params">(Thread* thread, ThreadType thr_type,</span></span></span><br><span class="line"><span class="params"><span class="function">                       <span class="type">size_t</span> req_stack_size)</span> </span>&#123;</span><br><span class="line">  <span class="built_in">assert</span>(thread-&gt;<span class="built_in">osthread</span>() == <span class="literal">NULL</span>, <span class="string">&quot;caller responsible&quot;</span>);</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  <span class="comment">// set the correct thread state</span></span><br><span class="line">  osthread-&gt;<span class="built_in">set_thread_type</span>(thr_type);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Initial state is ALLOCATED but not INITIALIZED</span></span><br><span class="line">  osthread-&gt;<span class="built_in">set_state</span>(ALLOCATED);</span><br><span class="line"></span><br><span class="line">  thread-&gt;<span class="built_in">set_osthread</span>(osthread);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// init thread attributes</span></span><br><span class="line">  <span class="type">pthread_attr_t</span> attr;</span><br><span class="line">  <span class="built_in">pthread_attr_init</span>(&amp;attr);</span><br><span class="line">  <span class="built_in">pthread_attr_setdetachstate</span>(&amp;attr, PTHREAD_CREATE_DETACHED);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Calculate stack size if it&#x27;s not specified by caller.</span></span><br><span class="line">  <span class="type">size_t</span> stack_size = os::Posix::<span class="built_in">get_initial_stack_size</span>(thr_type, req_stack_size);</span><br><span class="line">  <span class="comment">// In glibc versions prior to 2.27 the guard size mechanism</span></span><br><span class="line">  <span class="comment">// is not implemented properly. The posix standard requires adding</span></span><br><span class="line">  <span class="comment">// the size of the guard pages to the stack size, instead Linux</span></span><br><span class="line">  <span class="comment">// takes the space out of &#x27;stacksize&#x27;. Thus we adapt the requested</span></span><br><span class="line">  <span class="comment">// stack_size by the size of the guard pages to mimic proper</span></span><br><span class="line">  <span class="comment">// behaviour. However, be careful not to end up with a size</span></span><br><span class="line">  <span class="comment">// of zero due to overflow. Don&#x27;t add the guard page in that case.</span></span><br><span class="line">  <span class="type">size_t</span> guard_size = os::Linux::<span class="built_in">default_guard_size</span>(thr_type);</span><br><span class="line">  <span class="comment">// Configure glibc guard page. Must happen before calling</span></span><br><span class="line">  <span class="comment">// get_static_tls_area_size(), which uses the guard_size.</span></span><br><span class="line">  <span class="built_in">pthread_attr_setguardsize</span>(&amp;attr, guard_size);</span><br><span class="line"></span><br><span class="line">  <span class="type">size_t</span> stack_adjust_size = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">if</span> (AdjustStackSizeForTLS) &#123;</span><br><span class="line">    <span class="comment">// Adjust the stack_size for on-stack TLS - see get_static_tls_area_size().</span></span><br><span class="line">    stack_adjust_size += <span class="built_in">get_static_tls_area_size</span>(&amp;attr);</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    stack_adjust_size += guard_size;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  stack_adjust_size = <span class="built_in">align_up</span>(stack_adjust_size, os::<span class="built_in">vm_page_size</span>());</span><br><span class="line">  <span class="keyword">if</span> (stack_size &lt;= SIZE_MAX - stack_adjust_size) &#123;</span><br><span class="line">    stack_size += stack_adjust_size;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">assert</span>(<span class="built_in">is_aligned</span>(stack_size, os::<span class="built_in">vm_page_size</span>()), <span class="string">&quot;stack_size not aligned&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="type">int</span> status = <span class="built_in">pthread_attr_setstacksize</span>(&amp;attr, stack_size);</span><br><span class="line">  <span class="keyword">if</span> (status != <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="comment">// pthread_attr_setstacksize() function can fail</span></span><br><span class="line">    <span class="comment">// if the stack size exceeds a system-imposed limit.</span></span><br><span class="line">    <span class="built_in">assert_status</span>(status == EINVAL, status, <span class="string">&quot;pthread_attr_setstacksize&quot;</span>);</span><br><span class="line">    <span class="built_in">log_warning</span>(os, thread)(<span class="string">&quot;The %sthread stack size specified is invalid: &quot;</span> SIZE_FORMAT <span class="string">&quot;k&quot;</span>,</span><br><span class="line">                            (thr_type == compiler_thread) ? <span class="string">&quot;compiler &quot;</span> : ((thr_type == java_thread) ? <span class="string">&quot;&quot;</span> : <span class="string">&quot;VM &quot;</span>),</span><br><span class="line">                            stack_size / K);</span><br><span class="line">    thread-&gt;<span class="built_in">set_osthread</span>(<span class="literal">NULL</span>);</span><br><span class="line">    <span class="keyword">delete</span> osthread;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  ThreadState state;</span><br><span class="line"></span><br><span class="line">  &#123;</span><br><span class="line">    ResourceMark rm;</span><br><span class="line">    <span class="type">pthread_t</span> tid;</span><br><span class="line">    <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">    <span class="type">int</span> limit = <span class="number">3</span>;</span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">      ret = <span class="built_in">pthread_create</span>(&amp;tid, &amp;attr, (<span class="type">void</span>* (*)(<span class="type">void</span>*)) thread_native_entry, thread);</span><br><span class="line">    &#125; <span class="keyword">while</span> (ret == EAGAIN &amp;&amp; limit-- &gt; <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="type">char</span> buf[<span class="number">64</span>];</span><br><span class="line">    <span class="keyword">if</span> (ret == <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="built_in">log_info</span>(os, thread)(<span class="string">&quot;Thread \&quot;%s\&quot; started (pthread id: &quot;</span> UINTX_FORMAT <span class="string">&quot;, attributes: %s). &quot;</span>,</span><br><span class="line">                           thread-&gt;<span class="built_in">name</span>(), (uintx) tid, os::Posix::<span class="built_in">describe_pthread_attr</span>(buf, <span class="built_in">sizeof</span>(buf), &amp;attr));</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="built_in">log_warning</span>(os, thread)(<span class="string">&quot;Failed to start thread \&quot;%s\&quot; - pthread_create failed (%s) for attributes: %s.&quot;</span>,</span><br><span class="line">                              thread-&gt;<span class="built_in">name</span>(), os::<span class="built_in">errno_name</span>(ret), os::Posix::<span class="built_in">describe_pthread_attr</span>(buf, <span class="built_in">sizeof</span>(buf), &amp;attr));</span><br><span class="line">      <span class="comment">// Log some OS information which might explain why creating the thread failed.</span></span><br><span class="line">      <span class="built_in">log_info</span>(os, thread)(<span class="string">&quot;Number of threads approx. running in the VM: %d&quot;</span>, Threads::<span class="built_in">number_of_threads</span>());</span><br><span class="line">      <span class="function">LogStream <span class="title">st</span><span class="params">(Log(os, thread)::info())</span></span>;</span><br><span class="line">      os::Posix::<span class="built_in">print_rlimit_info</span>(&amp;st);</span><br><span class="line">      os::<span class="built_in">print_memory_info</span>(&amp;st);</span><br><span class="line">      os::Linux::<span class="built_in">print_proc_sys_info</span>(&amp;st);</span><br><span class="line">      os::Linux::<span class="built_in">print_container_info</span>(&amp;st);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">pthread_attr_destroy</span>(&amp;attr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (ret != <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">// Need to clean up stuff we&#x27;ve allocated so far</span></span><br><span class="line">      thread-&gt;<span class="built_in">set_osthread</span>(<span class="literal">NULL</span>);</span><br><span class="line">      <span class="keyword">delete</span> osthread;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Store pthread info into the OSThread</span></span><br><span class="line">    osthread-&gt;<span class="built_in">set_pthread_id</span>(tid);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Wait until child thread is either initialized or aborted</span></span><br><span class="line">    &#123;</span><br><span class="line">      Monitor* sync_with_child = osthread-&gt;<span class="built_in">startThread_lock</span>();</span><br><span class="line">      <span class="function">MutexLocker <span class="title">ml</span><span class="params">(sync_with_child, Mutex::_no_safepoint_check_flag)</span></span>;</span><br><span class="line">      <span class="keyword">while</span> ((state = osthread-&gt;<span class="built_in">get_state</span>()) == ALLOCATED) &#123;</span><br><span class="line">        sync_with_child-&gt;<span class="built_in">wait_without_safepoint_check</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="comment">// The thread is returned suspended (in state INITIALIZED),</span></span><br><span class="line">  <span class="comment">// and is started higher up in the call chain</span></span><br><span class="line">  <span class="built_in">assert</span>(state == INITIALIZED, <span class="string">&quot;race condition&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>osthread-&gt;set_state(ALLOCATED)，初始化已分配的状态，但此时并没有初始化。</li><li>pthread_create unix系统线程创建函数</li><li>thread_native_entry(旧:java_start)实际线程创建方法(Thread start routine for all newly created threads)</li></ul><h3 id="thread-native-entry"><a href="#thread-native-entry" class="headerlink" title="thread_native_entry"></a>thread_native_entry</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> *<span class="title">thread_native_entry</span><span class="params">(Thread *thread)</span> </span>&#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  <span class="type">int</span> pid = os::<span class="built_in">current_process_id</span>();</span><br><span class="line">  <span class="type">int</span> random = ((pid ^ counter++) &amp; <span class="number">7</span>) * <span class="number">128</span>;</span><br><span class="line">  <span class="type">void</span> *stackmem = <span class="built_in">alloca</span>(random != <span class="number">0</span> ? random : <span class="number">1</span>); <span class="comment">// ensure we allocate &gt; 0</span></span><br><span class="line">  <span class="comment">// Ensure the alloca result is used in a way that prevents the compiler from eliding it.</span></span><br><span class="line">  *(<span class="type">char</span> *)stackmem = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">  thread-&gt;<span class="built_in">initialize_thread_current</span>();</span><br><span class="line"></span><br><span class="line">  OSThread* osthread = thread-&gt;<span class="built_in">osthread</span>();</span><br><span class="line">  Monitor* sync = osthread-&gt;<span class="built_in">startThread_lock</span>();</span><br><span class="line"></span><br><span class="line">  osthread-&gt;<span class="built_in">set_thread_id</span>(os::<span class="built_in">current_thread_id</span>());</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (UseNUMA) &#123;</span><br><span class="line">    <span class="type">int</span> lgrp_id = os::<span class="built_in">numa_get_group_id</span>();</span><br><span class="line">    <span class="keyword">if</span> (lgrp_id != <span class="number">-1</span>) &#123;</span><br><span class="line">      thread-&gt;<span class="built_in">set_lgrp_id</span>(lgrp_id);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// initialize signal mask for this thread</span></span><br><span class="line">  PosixSignals::<span class="built_in">hotspot_sigmask</span>(thread);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// initialize floating point control register</span></span><br><span class="line">  os::Linux::<span class="built_in">init_thread_fpu_state</span>();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// handshaking with parent thread</span></span><br><span class="line">  &#123;</span><br><span class="line">    <span class="function">MutexLocker <span class="title">ml</span><span class="params">(sync, Mutex::_no_safepoint_check_flag)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// notify parent thread</span></span><br><span class="line">    osthread-&gt;<span class="built_in">set_state</span>(INITIALIZED);</span><br><span class="line">    sync-&gt;<span class="built_in">notify_all</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// wait until os::start_thread()</span></span><br><span class="line">    <span class="keyword">while</span> (osthread-&gt;<span class="built_in">get_state</span>() == INITIALIZED) &#123;</span><br><span class="line">      sync-&gt;<span class="built_in">wait_without_safepoint_check</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="built_in">log_info</span>(os, thread)(<span class="string">&quot;Thread is alive (tid: &quot;</span> UINTX_FORMAT <span class="string">&quot;, pthread id: &quot;</span> UINTX_FORMAT <span class="string">&quot;).&quot;</span>,</span><br><span class="line">    os::<span class="built_in">current_thread_id</span>(), (uintx) <span class="built_in">pthread_self</span>());</span><br><span class="line"></span><br><span class="line">  <span class="built_in">assert</span>(osthread-&gt;<span class="built_in">pthread_id</span>() != <span class="number">0</span>, <span class="string">&quot;pthread_id was not set as expected&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// call one more level start routine</span></span><br><span class="line">  thread-&gt;<span class="built_in">call_run</span>();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Note: at this point the thread object may already have deleted itself.</span></span><br><span class="line">  <span class="comment">// Prevent dereferencing it from here on out.</span></span><br><span class="line">  thread = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">  <span class="built_in">log_info</span>(os, thread)(<span class="string">&quot;Thread finished (tid: &quot;</span> UINTX_FORMAT <span class="string">&quot;, pthread id: &quot;</span> UINTX_FORMAT <span class="string">&quot;).&quot;</span>,</span><br><span class="line">    os::<span class="built_in">current_thread_id</span>(), (uintx) <span class="built_in">pthread_self</span>());</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>osthread-&gt;set_state(INITIALIZED);</code>：JVM 设置线程状态，INITIALIZED 初始化完成。</li><li><code>sync-&gt;notify_all()</code>：唤醒线程</li><li><code>osthread-&gt;get_state() == INITIALIZED</code>：循环等待条件</li><li><code>thread-&gt;call_run();</code>：是等待线程唤醒后，也就是状态变更后，才能执行到。这在我们的线程执行UML图中，也有所体现</li></ul><h2 id="启动线程"><a href="#启动线程" class="headerlink" title="启动线程"></a>启动线程</h2><h3 id="waiting"><a href="#waiting" class="headerlink" title="waiting"></a>waiting</h3><p>等地更新</p>]]></content>
    
    
    <summary type="html">Thread.start()是怎么让线程启动的</summary>
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="多线程" scheme="https://www.ripic.site/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
    
    <category term="Java" scheme="https://www.ripic.site/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>通过Drone CI将Gitea托管的Hexo部署到Vercel</title>
    <link href="https://www.ripic.site/archives/2023/01/28/deploy-hexo-to-Vercel-via-Drone.html"/>
    <id>https://www.ripic.site/archives/2023/01/28/deploy-hexo-to-Vercel-via-Drone.html</id>
    <published>2023-01-28T18:03:18.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>随着即将毕业，GitHub学生优惠也即将到期，很多特权不能再使用，这其中就包括GitHub Action和私有仓库GitHub Page。为了打破这种束缚，同时也希望能把自己的数据掌握在自己手里，于是使用Gitea搭建了自己的私有Git仓库。</p><p>随之而来的问题就是，私有部署无法使用GitHub Action和诸如Vercel、Netfily这些三方的部署平台，于是采用Drone + Gitea实现流水线的搭建，通过FTP将文件传输到服务器上。但是由于域名备案的原因，国内的CDN和服务器再一次无法使用。于是目光再次瞄准Vercel。</p><p>Vercel基于亚马逊的网络搭建了自己的<strong>泛播网络</strong>，对于不同的网络环境（包括国内）都十分友好。但是目前Vercel只支持关联几家主流的Git提供商，于是瞄准了Vercel提供的CLI工具。通过CLI工具来实现流水线部署的工作。</p><p>这里我已经打包好了Vercel需要用到的<a href="https://hub.docker.com/r/ripic/vercel-cli">镜像</a>，内置如下环境：</p><ul><li>nodejs  18.13.0</li><li>Vercel CLI 28.13.2</li></ul><div class="tag-plugin note" color="orange"><div class="body"><p>此处默认您已经搭建好了Gitea、Drone环境，并已成功关联Drone与Gitea。成功上传了您的Hexo代码到Gitea中</p></div></div><p>在hexo根目录下增加<code>.drone.yml</code>文件，代码如下：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><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="attr">kind:</span> <span class="string">pipeline</span></span><br><span class="line"><span class="attr">type:</span> <span class="string">docker</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">blog-job</span></span><br><span class="line"><span class="attr">steps:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Push</span> <span class="string">to</span> <span class="string">Vercel</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">ripic/vercel-cli:vercel28.13.2-node18.13.0-alpine</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">VERCEL_TOKEN:</span></span><br><span class="line">          <span class="attr">from_secret:</span> <span class="string">vercel_token</span></span><br><span class="line">      <span class="attr">VERCEL_ORG_ID:</span></span><br><span class="line">          <span class="attr">from_secret:</span> <span class="string">vercel_org_id</span></span><br><span class="line">      <span class="attr">VERCEL_PROJECT_ID:</span></span><br><span class="line">          <span class="attr">from_secret:</span> <span class="string">vercel_project_id</span></span><br><span class="line">    <span class="attr">commands:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">vercel</span> <span class="string">pull</span> <span class="string">--yes</span> <span class="string">--environment=production</span> <span class="string">--token=$VERCEL_TOKEN</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">vercel</span> <span class="string">build</span> <span class="string">--prod</span> <span class="string">--token=$VERCEL_TOKEN</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">vercel</span> <span class="string">deploy</span> <span class="string">--prebuilt</span> <span class="string">--prod</span> <span class="string">--token=$VERCEL_TOKEN</span></span><br><span class="line"><span class="attr">trigger:</span></span><br><span class="line">  <span class="attr">event:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">push</span></span><br></pre></td></tr></table></figure><div class="tag-plugin note" color="red"><div class="body"><p>获取vercel_org_id、vercel_project_id步骤不可省略！</p></div></div><p>如已有Vercel项目，请直接将<code>vercel_org_id</code>、<code>vercel_project_id</code>配置进Drone CI的Secret中。如果不存在项目，请本地安装Vercel CLI工具，新建文件夹，执行<code>vercel login</code>进行登录，运行<code>vercel link</code>按照提示新建一个项目，<code>vercel_org_id</code>、<code>vercel_project_id</code>将会保存在<code>.vercel/project.json</code>文件中。</p><p>在<a href="https://vercel.com/account/tokens">https://vercel.com/account/tokens</a>获取<code>vercel_token</code>并保存。</p><p>启用Drone，并上传Git，部署即可自动进行。</p>]]></content>
    
    
    <summary type="html">Gitea + Drone CI + Vercel = Gitea Pages</summary>
    
    
    
    <category term="教程" scheme="https://www.ripic.site/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Drone" scheme="https://www.ripic.site/tags/Drone/"/>
    
    <category term="gitea" scheme="https://www.ripic.site/tags/gitea/"/>
    
    <category term="vercel" scheme="https://www.ripic.site/tags/vercel/"/>
    
  </entry>
  
  <entry>
    <title>优雅的java controller实现（一）</title>
    <link href="https://www.ripic.site/archives/2023/01/27/better-controller-1.html"/>
    <id>https://www.ripic.site/archives/2023/01/27/better-controller-1.html</id>
    <published>2023-01-27T18:43:11.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>本系列预计分为三篇文章，本篇文章主要介绍java参数接收</p></blockquote><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本篇主要要介绍的就是controller层的处理，一个完整的后端请求由4部分组成：1. 接口地址(也就是URL地址)、2. 请求方式(一般就是get、post，当然还有put、delete)、3. 请求数据(request，有head跟body)、4. 响应数据(response)。</p><p>本篇文章主要从参数接收，参数校验，统一响应和异常处理四个方面进行介绍。</p><h2 id="Controller参数接收"><a href="#Controller参数接收" class="headerlink" title="Controller参数接收"></a>Controller参数接收</h2><p>常见的请求无非是post和get两种，这里直接使用代码说明</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="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/product/product-info&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProductInfoController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    ProductInfoService productInfoService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/findById&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ProductInfoQueryVo <span class="title function_">findById</span><span class="params">(Integer id)</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><h3 id="注解说明"><a href="#注解说明" class="headerlink" title="注解说明"></a>注解说明</h3><blockquote><ul><li>@RestController : @Controller + @ResponseBody，加上这个注解，springboot就会吧这个类当成controller进行处理，然后把所有返回的参数放到ResponseBody中</li><li>@RequestMapping：接受所有请求类型，参数为目录</li><li>@PostMapping&#x2F;@GetMapping：对应POST&#x2F;GET请求，参数为目录</li></ul></blockquote><h3 id="参数接收"><a href="#参数接收" class="headerlink" title="参数接收"></a>参数接收</h3><p>上述代码中介绍了直接接收参数的一种方法，在函数签名中写入变量即可进行处理，下面具体介绍：</p><h4 id="通过Controller的方法的形参接收"><a href="#通过Controller的方法的形参接收" class="headerlink" title="通过Controller的方法的形参接收"></a>通过Controller的方法的形参接收</h4><p>适用于get, post方式提交，post方式的时候编码方式需设置为：x-www-form-urlencoded转换为键值对形式，参数名必须完全相同才能映射到，不可以实现别名转换。</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="comment">/**</span></span><br><span class="line"><span class="comment">  * 1.直接把表单的参数写在Controller相应的方法的形参中</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@param</span> username</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@param</span> password</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">@RequestMapping(&quot;/addUser1&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">addUser1</span><span class="params">(String username,String password)</span> &#123;</span><br><span class="line">     System.out.println(<span class="string">&quot;username is:&quot;</span>+username);</span><br><span class="line">     System.out.println(<span class="string">&quot;password is:&quot;</span>+password);</span><br><span class="line">     <span class="keyword">return</span> <span class="string">&quot;demo/index&quot;</span>;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure><h4 id="通过HttpServletRequest接收"><a href="#通过HttpServletRequest接收" class="headerlink" title="通过HttpServletRequest接收"></a>通过HttpServletRequest接收</h4><p>post方式和get方式都可以, 但不能接收json, post方式的时候编码方式需设置为：x-www-form-urlencoded转换为键值对。</p><div class="tag-plugin note" color="red"><div class="body"><p>在使用本方法时应注意，如果获取的参数不存在可能会抛出空指针异常</p></div></div><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="comment">/**</span></span><br><span class="line"><span class="comment">  * 2、通过HttpServletRequest接收</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@param</span> request</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">@RequestMapping(&quot;/addUser2&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">addUser2</span><span class="params">(HttpServletRequest request)</span> &#123;</span><br><span class="line">     String username=request.getParameter(<span class="string">&quot;username&quot;</span>);</span><br><span class="line">     String password=request.getParameter(<span class="string">&quot;password&quot;</span>);</span><br><span class="line">     System.out.println(<span class="string">&quot;username is:&quot;</span>+username);</span><br><span class="line">     System.out.println(<span class="string">&quot;password is:&quot;</span>+password);</span><br><span class="line">     <span class="keyword">return</span> <span class="string">&quot;demo/index&quot;</span>;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure><h4 id="通过javabean接收"><a href="#通过javabean接收" class="headerlink" title="通过javabean接收"></a>通过javabean接收</h4><p>post方式和get方式都可以。参数?key1&#x3D;val1&amp;key2&#x3D;val2的方式加在url后面即可。post方式不想让参数拼接在url后面的话，可以将参数放在body中，编码方式需设置为：x-www-form-urlencoded。</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="meta">@RequestMapping(&quot;/doLogin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> User <span class="title function_">doLogin</span><span class="params">(User u)</span> &#123;</span><br><span class="line"></span><br><span class="line">    logger.info(<span class="string">&quot;name: &quot;</span> + u.getName());</span><br><span class="line">    logger.info(<span class="string">&quot;pswd: &quot;</span> + u.getPswd());</span><br><span class="line"></span><br><span class="line">    <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line">    user.setName(u.getName());</span><br><span class="line">    user.setPswd(u.getPswd());</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> user;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="通过javabean接收json"><a href="#通过javabean接收json" class="headerlink" title="通过javabean接收json"></a>通过javabean接收json</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/doLogin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@ResponseBody</span> User <span class="title function_">doLogin</span><span class="params">(<span class="meta">@RequestBody</span> User u)</span> &#123;</span><br><span class="line">    logger.info(<span class="string">&quot;name: &quot;</span> + u.getName());</span><br><span class="line">    logger.info(<span class="string">&quot;pswd: &quot;</span> + u.getPswd());</span><br><span class="line">    <span class="keyword">return</span> u;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="通过map接收json"><a href="#通过map接收json" class="headerlink" title="通过map接收json"></a>通过map接收json</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/doLogin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@ResponseBody</span> User <span class="title function_">doLogin</span><span class="params">(<span class="meta">@RequestBody</span> Map&lt;String, String&gt; u)</span> &#123;</span><br><span class="line"></span><br><span class="line">    logger.info(<span class="string">&quot;name: &quot;</span> + u.get(<span class="string">&quot;name&quot;</span>));</span><br><span class="line">    logger.info(<span class="string">&quot;pswd: &quot;</span> + u.get(<span class="string">&quot;pswd&quot;</span>));</span><br><span class="line"></span><br><span class="line">    <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line">    user.setName(u.get(<span class="string">&quot;name&quot;</span>));</span><br><span class="line">    user.setPswd(u.get(<span class="string">&quot;pswd&quot;</span>));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> user;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="tag-plugin note" color="yellow"><div class="body"><p>注意Controller上标注了@RestController，这样相当于Controller的所有方法都标注了@ResponseBody，但是接收参数的@RequestBody还是需要手动协商</p></div></div><h4 id="通过-PathVariable获取参数"><a href="#通过-PathVariable获取参数" class="headerlink" title="通过@PathVariable获取参数"></a>通过@PathVariable获取参数</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></pre></td><td class="code"><pre><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> username</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> password</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">@RequestMapping(value=&quot;/addUser4/&#123;username&#125;/&#123;password&#125;&quot;,method=RequestMethod.GET)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">addUser4</span><span class="params">(<span class="meta">@PathVariable</span> String username,<span class="meta">@PathVariable</span> String password)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;username is:&quot;</span>+username);</span><br><span class="line">        System.out.println(<span class="string">&quot;password is:&quot;</span>+password);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h4 id="用注解-RequestParam绑定请求参数到方法入参"><a href="#用注解-RequestParam绑定请求参数到方法入参" class="headerlink" title="用注解@RequestParam绑定请求参数到方法入参"></a>用注解@RequestParam绑定请求参数到方法入参</h4><p>post方式的时候编码方式需设置为：x-www-form-urlencoded, 不能接受json</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">@RequestMapping(&quot;/doLogin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> User <span class="title function_">doLogin</span><span class="params">(<span class="meta">@RequestParam(value=&quot;name&quot;)</span> String username, <span class="meta">@RequestParam(value=&quot;pswd&quot;)</span> String password)</span> &#123;</span><br><span class="line">    logger.info(<span class="string">&quot;name: &quot;</span> + username);</span><br><span class="line">    logger.info(<span class="string">&quot;psed: &quot;</span> + password);</span><br><span class="line">    <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line">    user.setPswd(password);</span><br><span class="line">    user.setName(username);</span><br><span class="line">    <span class="keyword">return</span> user;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="更多"><a href="#更多" class="headerlink" title="更多"></a>更多</h3><p>对于复杂的参数接收，可以采用不同实体类嵌套的方法进行解析，举例说明：</p><h4 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h4><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;s&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="attr">&quot;clas&quot;</span><span class="punctuation">:</span> <span class="string">&quot;s1&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;age&quot;</span><span class="punctuation">:</span> <span class="string">&quot;11&quot;</span><span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;name&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;susq&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;pswd&quot;</span> <span class="punctuation">:</span> <span class="number">1233</span></span><br><span class="line"><span class="punctuation">&#125;</span></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><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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">public</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    Student s;</span><br><span class="line">    String name;</span><br><span class="line">    String pswd;</span><br><span class="line">    <span class="comment">// getter  setter</span></span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//Student是另一单独的对象</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">    String clas;</span><br><span class="line">    <span class="type">int</span> age;</span><br><span class="line">    <span class="comment">// getter setter</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">介绍java参数接收</summary>
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Controller" scheme="https://www.ripic.site/tags/Controller/"/>
    
  </entry>
  
  <entry>
    <title>随便聊聊</title>
    <link href="https://www.ripic.site/archives/2023/01/20/Inspirational-words-on-the-road-of-development.html"/>
    <id>https://www.ripic.site/archives/2023/01/20/Inspirational-words-on-the-road-of-development.html</id>
    <published>2023-01-20T17:39:07.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<div class="tag-plugin note" color="green"><div class="body"><p>正因为你优秀，所以难以卓越！</p></div></div><span id="more"></span><p>刚开始听这句话还在初中，既不卓越、也不优秀，甚至可能还有点笨！但突然从某次爬到班级的前几名后，开始喜欢上了这种感觉，原来前面的风景是如此灿烂😜！</p><p>之所以突然想起来重新提到这个话题，是因为最近在看笔记的时候偶然又发现了这句话，忍不住就简单说一下内心的想法吧！</p><p>优秀和卓越差的不是一个等级，当你感觉自己优秀后，还能保持空瓶的心态开始，才能逐步的像卓越迈进，并漫漫长！是不小时候更容易学会更多的知识，但越大越笨了！人可能很容易被自己的年纪大了，当成长者。却很少能保持一个低姿态谦卑的心态，不断的学习。所以最后，放不下自己，也拾不起能力。</p><p>喜欢一句话，蓝是天的颜色、红是火的象征，我不学大海抄袭天的蓝、也不学晚霞模拟火的红。我就是我，生命是我的、命运是我的。健身也是你的、学习也是你的，只要你有一个好心态，自然会走到前面卓越那里！</p><p>新的一年，加油！</p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin note&quot; color=&quot;green&quot;&gt;&lt;div class=&quot;body&quot;&gt;&lt;p&gt;正因为你优秀，所以难以卓越！&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</summary>
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
    <category term="闲聊" scheme="https://www.ripic.site/tags/%E9%97%B2%E8%81%8A/"/>
    
  </entry>
  
  <entry>
    <title>通过GitHub Action将hexo部署到腾讯云cos</title>
    <link href="https://www.ripic.site/archives/2023/01/04/deploy-hexo-to-cos-by-github-action.html"/>
    <id>https://www.ripic.site/archives/2023/01/04/deploy-hexo-to-cos-by-github-action.html</id>
    <published>2023-01-04T09:47:42.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<h2 id="创建hexo博客"><a href="#创建hexo博客" class="headerlink" title="创建hexo博客"></a>创建hexo博客</h2><p>首先安装nodejs和npm，建议使用nodejs 12版本，然后安装git。</p><p>具体步骤请参考：<a href="https://www.runoob.com/nodejs/nodejs-install-setup.html">nodejs安装</a>、<a href="https://www.runoob.com/git/git-install-setup.html">git安装</a></p><p>运行hexo安装命令，如果使用linux系统请切换为超级用户</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-cli -g</span><br></pre></td></tr></table></figure><p>进入新文件夹，打开终端，运行如下命令安装hexo</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo init &lt;project_name&gt;</span><br><span class="line">cd &lt;project_name&gt;</span><br><span class="line">npm install</span><br></pre></td></tr></table></figure><p>你可以运行如下命令验证是否初始化成功</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo s</span><br></pre></td></tr></table></figure><p>浏览器打开 localhost:4000 如果可以正常访问即代表搭建成功</p><h2 id="初始化git仓库，上传到github"><a href="#初始化git仓库，上传到github" class="headerlink" title="初始化git仓库，上传到github"></a>初始化git仓库，上传到github</h2><p>运行如下命令进行初始化</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git init</span><br><span class="line">git add .</span><br><span class="line">git commit -m &quot;commit&quot;</span><br><span class="line">git remote add origin &lt;git repo&gt;</span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure><p>至此，代码已经成功上传到github仓库。</p><h2 id="配置github-action自动构建并上传到cos"><a href="#配置github-action自动构建并上传到cos" class="headerlink" title="配置github action自动构建并上传到cos"></a>配置github action自动构建并上传到cos</h2><h3 id="配置腾讯云"><a href="#配置腾讯云" class="headerlink" title="配置腾讯云"></a>配置腾讯云</h3><ul><li>创建一个新的cos仓库，选择公共读私有写即可，记录地区信息和完整的cos名</li><li>腾讯云创建一组新的access_key和access_secret，并记录</li></ul><h3 id="创建github-secret"><a href="#创建github-secret" class="headerlink" title="创建github secret"></a>创建github secret</h3><ul><li>进入github仓库，点击<code>Settings</code>-<code>Secrets</code>-<code>Actions</code></li><li>点击<code>New repository secret</code>依次添加如下变量<ul><li><code>SECRETID</code>：对应腾讯云SecretId</li><li><code>SECRETKEY</code>：对应腾讯云SecretKey</li></ul></li></ul><h3 id="创建github-action"><a href="#创建github-action" class="headerlink" title="创建github action"></a>创建github action</h3><ul><li>依次点击<code>Actions</code>-<code>New workflow</code></li><li>点击蓝色的<code>set up a workflow yourself -&gt;</code></li><li>粘贴如下代码</li></ul><div class="tag-plugin note" color="red"><div class="title">注意</div><div class="body"><p>请修改BUCKET和REGION为你自己的信息</p></div></div><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><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="attr">name:</span> <span class="string">Blog</span> <span class="string">CI/CD</span></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">main</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">master</span></span><br><span class="line"><span class="attr">env:</span></span><br><span class="line">  <span class="attr">TZ:</span> <span class="string">Asia/Shanghai</span></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">blog-cicd:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">Hexo</span> <span class="string">blog</span> <span class="string">build</span> <span class="string">&amp;</span> <span class="string">deploy</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span> <span class="comment"># 使用最新的 Ubuntu 系统作为编译部署的环境</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Checkout</span> <span class="string">codes</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/checkout@v2</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Setup</span> <span class="string">node</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/setup-node@v1</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">node-version:</span> <span class="string">&quot;18.x&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Install</span> <span class="string">hexo</span> <span class="string">dependencies</span> <span class="string">&amp;&amp;</span> <span class="string">Generate</span> <span class="string">files</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">yarn</span> <span class="string">install</span> <span class="string">&amp;&amp;</span> <span class="string">yarn</span> <span class="string">run</span> <span class="string">build</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Install</span> <span class="string">coscmd</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">sudo</span> <span class="string">pip</span> <span class="string">install</span> <span class="string">coscmd</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Configure</span> <span class="string">coscmd</span></span><br><span class="line">        <span class="attr">env:</span></span><br><span class="line">          <span class="attr">SECRET_ID:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.SecretId</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">SECRET_KEY:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.SecretKey</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">BUCKET:</span> <span class="string">abc-xxxxxxxxxxxxxxx</span></span><br><span class="line">          <span class="attr">REGION:</span> <span class="string">ap-xxxxxx</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">coscmd</span> <span class="string">config</span> <span class="string">-a</span> <span class="string">$SECRET_ID</span> <span class="string">-s</span> <span class="string">$SECRET_KEY</span> <span class="string">-b</span> <span class="string">$BUCKET</span> <span class="string">-r</span> <span class="string">$REGION</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Upload</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">cd</span> <span class="string">./public</span> <span class="string">&amp;&amp;</span> <span class="string">coscmd</span> <span class="string">upload</span> <span class="string">-r</span> <span class="string">./</span> <span class="string">/</span></span><br></pre></td></tr></table></figure><ul><li>提交即可</li></ul><h3 id="腾讯云CDN绑定自定义域名"><a href="#腾讯云CDN绑定自定义域名" class="headerlink" title="腾讯云CDN绑定自定义域名"></a>腾讯云CDN绑定自定义域名</h3><ul><li>腾讯云COS开启静态网站托管</li><li>腾讯云CDN添加域名，源站选择COS-静态网站即可</li></ul>]]></content>
    
    
    <summary type="html">通过GitHub Action将hexo部署到腾讯云cos</summary>
    
    
    
    <category term="教程" scheme="https://www.ripic.site/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="hexo" scheme="https://www.ripic.site/tags/hexo/"/>
    
    <category term="GitHub Action" scheme="https://www.ripic.site/tags/GitHub-Action/"/>
    
  </entry>
  
  <entry>
    <title>Java整合rabbitMQ实现死信队列</title>
    <link href="https://www.ripic.site/archives/2022/12/27/java-rabbitmq.html"/>
    <id>https://www.ripic.site/archives/2022/12/27/java-rabbitmq.html</id>
    <published>2022-12-27T16:29:42.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>这里依旧使用 <code>springboot</code> 框架，同时使用spring提供的rabbitmq-starter来实现rabbitMQ死信队列。</p><span id="more"></span><h2 id="pom依赖"><a href="#pom依赖" class="headerlink" title="pom依赖"></a>pom依赖</h2><p>在项目依赖文件 <code>pom.xml</code> 添加下面的依赖</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp --&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-amqp<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.0.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><h2 id="配置rabbitmq信息"><a href="#配置rabbitmq信息" class="headerlink" title="配置rabbitmq信息"></a>配置rabbitmq信息</h2><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">admin</span></span><br><span class="line">    <span class="attr">publisher-returns:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">publisher-confirm-type:</span> <span class="string">correlated</span></span><br><span class="line">    <span class="attr">host:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">admin</span></span><br></pre></td></tr></table></figure><h2 id="消息可靠性保障"><a href="#消息可靠性保障" class="headerlink" title="消息可靠性保障"></a>消息可靠性保障</h2><p>消息可靠性需要在生产者与消费者两个地方进行配置，这里仅配置了生产者确认，后面单独开文章写一下消费者手动确认与重试机制的问题。</p><p>这里将 <code>publisher-returns</code>和 <code>publisher-confirm-type</code>配置了一下，保证在生产者产生消息之后消息中间件可以给程序反馈，确保生产者不丢消息（或者说，在生产者丢消息之后能够进行处理）。</p><p>在配置类里面配置回调逻辑：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RabbitTemplate <span class="title function_">createRabbitTemplate</span><span class="params">(ConnectionFactory connectionFactory)</span> &#123;</span><br><span class="line">        <span class="type">RabbitTemplate</span> <span class="variable">rabbitTemplate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RabbitTemplate</span>();</span><br><span class="line">        rabbitTemplate.setConnectionFactory(connectionFactory);</span><br><span class="line">        <span class="comment">// Mandatory为true时,消息通过交换器无法匹配到队列会返回给生产者，为false时匹配不到会直接被丢弃</span></span><br><span class="line">        rabbitTemplate.setMandatory(<span class="literal">true</span>);</span><br><span class="line">        rabbitTemplate.setConfirmCallback(<span class="keyword">new</span> <span class="title class_">RabbitTemplate</span>.ConfirmCallback() &#123;</span><br><span class="line">            <span class="comment">/**</span></span><br><span class="line"><span class="comment">             *  ConfirmCallback机制只确认消息是否到达exchange(交换器)，不保证消息可以路由到正确的queue;</span></span><br><span class="line"><span class="comment">             *  需要设置：publisher-confirm-type: CORRELATED；</span></span><br><span class="line"><span class="comment">             *  springboot版本较低 参数设置改成：publisher-confirms: true</span></span><br><span class="line"><span class="comment">             *</span></span><br><span class="line"><span class="comment">             *  以实现方法confirm中ack属性为标准，true到达</span></span><br><span class="line"><span class="comment">             *  config : 需要开启rabbitmq得ack publisher-confirm-type</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">confirm</span><span class="params">(CorrelationData correlationData, <span class="type">boolean</span> ack, String cause)</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (ack) &#123;</span><br><span class="line">                    log.info(<span class="string">&quot;消息发送成功:correlationData(&#123;&#125;),ack(&#123;&#125;),cause(&#123;&#125;)&quot;</span>, correlationData, ack, cause);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    log.error(<span class="string">&quot;消息发送失败:correlationData(&#123;&#125;),ack(&#123;&#125;),cause(&#123;&#125;)&quot;</span>, correlationData, ack, cause);</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">        rabbitTemplate.setReturnsCallback(<span class="keyword">new</span> <span class="title class_">RabbitTemplate</span>.ReturnsCallback() &#123;</span><br><span class="line">            <span class="comment">/**</span></span><br><span class="line"><span class="comment">             *  ReturnsCallback 消息机制用于处理一个不可路由的消息。在某些情况下，如果我们在发送消息的时候，当前的 exchange 不存在或者指定路由 key 路由不到，这个时候我们需要监听这种不可达的消息</span></span><br><span class="line"><span class="comment">             *   就需要这种return机制</span></span><br><span class="line"><span class="comment">             *</span></span><br><span class="line"><span class="comment">             *  config : 需要开启rabbitmq发送失败回退; publisher-returns 或rabbitTemplate.setMandatory(true); 设置为true</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">returnedMessage</span><span class="params">(ReturnedMessage returned)</span> &#123;</span><br><span class="line"><span class="comment">//                实现接口ReturnCallback，重写 returnedMessage() 方法，</span></span><br><span class="line"><span class="comment">//                方法有五个参数</span></span><br><span class="line"><span class="comment">//                message（消息体）、</span></span><br><span class="line"><span class="comment">//                replyCode（响应code）、</span></span><br><span class="line"><span class="comment">//                replyText（响应内容）、</span></span><br><span class="line"><span class="comment">//                exchange（交换机）、</span></span><br><span class="line"><span class="comment">//                routingKey（队列）。</span></span><br><span class="line"></span><br><span class="line">                log.info(<span class="string">&quot;ReturnsCallback    returned : &#123;&#125;&quot;</span>, returned);</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">return</span> rabbitTemplate;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>通过 <code>@Bean</code>注解把 <code>RabbitTemplate</code>交给spring容器管理，配置确认逻辑。</p><h2 id="绑定消息交换机和消息队列"><a href="#绑定消息交换机和消息队列" class="headerlink" title="绑定消息交换机和消息队列"></a>绑定消息交换机和消息队列</h2><p>在绑定之前，我们需要首先进行创建，创建若干个“业务”消息队列，同时配置私信队列，便于消息中间件在处理失败的过程中能够可以进行“兜底”处理。</p><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="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> Exchange <span class="title function_">deadLetterExchange</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> ExchangeBuilder</span><br><span class="line">            .topicExchange(<span class="string">&quot;dead-letter-exchange&quot;</span>)</span><br><span class="line">            .durable(<span class="literal">true</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="keyword">public</span> Queue <span class="title function_">deadLetterQueue</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> QueueBuilder</span><br><span class="line">            .durable(<span class="string">&quot;dead-letter-queue&quot;</span>)</span><br><span class="line">            .build();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里同样使用 <code>@Bean</code>注解交给Spring容器管理，然后我们对上述内容执行绑定。</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">@Bean</span></span><br><span class="line"><span class="keyword">public</span> Binding <span class="title function_">userDeadLetterBinding</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> BindingBuilder</span><br><span class="line">            .bind(deadLetterQueue())</span><br><span class="line">            .to(deadLetterExchange())</span><br><span class="line">            .with(<span class="string">&quot;dead-letter-routing-key&quot;</span>)</span><br><span class="line">            .noargs();</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>with中的参数为routingKey，可以进行自定义，在转入死信队列的时候会携带这个参数。</p><ul><li>创建“业务”消息交换机</li></ul><p>这里使用了topic类型的交换机，具体信息暂时挖个坑，后面更新文章填坑吧。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">TopicExchange <span class="title function_">exchange</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">TopicExchange</span>(<span class="string">&quot;topic-ex&quot;</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> Queue <span class="title function_">firstQueue</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> QueueBuilder.durable(<span class="string">&quot;first-queue&quot;</span>)</span><br><span class="line">            .withArgument(<span class="string">&quot;x-dead-letter-exchange&quot;</span>, <span class="string">&quot;dead-letter-exchange&quot;</span>)</span><br><span class="line">            <span class="comment">//声明该队列死信消息在交换机的 路由键</span></span><br><span class="line">            .withArgument(<span class="string">&quot;x-dead-letter-routing-key&quot;</span>, <span class="string">&quot;dead-letter-routing-key&quot;</span>)</span><br><span class="line">            .build();</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">Binding <span class="title function_">bindingExchangeMessage</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> BindingBuilder.bind(firstQueue()).to(exchange()).with(<span class="string">&quot;first-queue&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里注意，由于是topic交换机，需要保证routingKey与消息队列的一致，才能正确把消息投入到指定的队列。</p><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">test</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">messageData</span> <span class="operator">=</span> <span class="string">&quot;message: rabbitmq message&quot;</span>;</span><br><span class="line">    Map&lt;String, Object&gt; manMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    manMap.put(<span class="string">&quot;messageData&quot;</span>, messageData);</span><br><span class="line">    rabbitTemplate.convertAndSend(<span class="string">&quot;topic-ex&quot;</span>, <span class="string">&quot;first-queue&quot;</span>, manMap, <span class="keyword">new</span> <span class="title class_">CorrelationData</span>(<span class="string">&quot;1001&quot;</span>));</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;ok&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>访问对应的地址，即可将消息投入到指定的消息队列了。</p><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RabbitListener(queues = &quot;first-queue&quot;)</span></span><br><span class="line"><span class="meta">@RabbitHandler</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">receiver</span><span class="params">(<span class="meta">@Payload</span> HashMap dataMsg, Channel channel, Message message)</span> <span class="keyword">throws</span> IOException, InterruptedException &#123;</span><br><span class="line">    <span class="type">long</span> <span class="variable">deliveryTag</span> <span class="operator">=</span> message.getMessageProperties().getDeliveryTag();</span><br><span class="line">    log.info(<span class="string">&quot;消费者 deliveryTag:&#123;&#125; dataMsg:&#123;&#125; &quot;</span>,deliveryTag ,dataMsg);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将消费者在程序初始化的时候保持后台运行，即可正常消费消息。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;这里依旧使用 &lt;code&gt;springboot&lt;/code&gt; 框架，同时使用spring提供的rabbitmq-starter来实现rabbitMQ死信队列。&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="rabbitmq" scheme="https://www.ripic.site/tags/rabbitmq/"/>
    
  </entry>
  
  <entry>
    <title>Java实现文件上传功能</title>
    <link href="https://www.ripic.site/archives/2022/12/26/how-to-use-Java-to-implement-the-function-of-uploading-files.html"/>
    <id>https://www.ripic.site/archives/2022/12/26/how-to-use-Java-to-implement-the-function-of-uploading-files.html</id>
    <published>2022-12-26T14:06:55.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>在日常的开发中，经常会出现图片上传和保存相关的内容，这里使用 <code>springboot</code> + <code>upyun</code> 为例，简单记录一下</p><span id="more"></span><p>首先编写upyun配置类</p><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/image&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">httpUpload</span><span class="params">(<span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file)</span> <span class="keyword">throws</span> IOException, UpException &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> file.getOriginalFilename();</span><br><span class="line">    <span class="keyword">if</span> (fileName == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.result(<span class="number">502</span>, <span class="string">&quot;图片不合法&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    String[] split = fileName.split(<span class="string">&quot;\\.&quot;</span>);</span><br><span class="line">    <span class="type">String</span> <span class="variable">suffix</span> <span class="operator">=</span> split[split.length - <span class="number">1</span>];</span><br><span class="line">    <span class="type">String</span> <span class="variable">filePath</span> <span class="operator">=</span> <span class="string">&quot;/upload/&quot;</span> + type + <span class="string">&quot;/&quot;</span> + IdUtil.randomUUID() + <span class="string">&quot;.&quot;</span> + suffix;</span><br><span class="line">    <span class="type">Response</span> <span class="variable">response</span> <span class="operator">=</span> restManager.writeFile(filePath, file.getInputStream(), <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;());</span><br><span class="line">    <span class="keyword">if</span> (response.code() != <span class="number">200</span>) &#123;</span><br><span class="line">        log.error(response.toString());</span><br><span class="line">        <span class="keyword">return</span> R.result(<span class="number">503</span>, <span class="string">&quot;上游接口错误，请与技术支持联系&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这里使用 <code>MultipartFile</code> 接收文件，简单转化为 <code>file.getInputStream()</code> 即可。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在日常的开发中，经常会出现图片上传和保存相关的内容，这里使用 &lt;code&gt;springboot&lt;/code&gt; + &lt;code&gt;upyun&lt;/code&gt; 为例，简单记录一下&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="文件上传" scheme="https://www.ripic.site/tags/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0/"/>
    
  </entry>
  
  <entry>
    <title>MySQL分页查询优化</title>
    <link href="https://www.ripic.site/archives/2022/12/18/mysql-paging-query-optimization.html"/>
    <id>https://www.ripic.site/archives/2022/12/18/mysql-paging-query-optimization.html</id>
    <published>2022-12-18T09:43:43.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>当需要从数据库查询的表有上万条记录的时候，一次性查询所有结果会变得很慢，特别是随着数据量的增加特别明显，这时需要使用分页查询。对于数据库分页查询，也有很多种方法和优化的点。下面简单说一下我知道的一些方法。</p><span id="more"></span><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><p>为了能够列举出一些优化测试，下面对测试表进行一些说明</p><ul><li>表名：order_history</li><li>描述：记录业务订单的历史表</li><li>主要字段：unsigned int id，tinyint(4) int type</li><li>具体字段：该表一共包含37个字段，不包含text等大型数据，最大为varchar(500)，id字段为索引，且为递增。</li><li>数据量：5709294</li><li>MySQL版本：5.7.16</li></ul><p>运行三次下面的语句：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="built_in">count</span>(<span class="operator">*</span>) <span class="keyword">from</span> orders_history;</span><br></pre></td></tr></table></figure><p>得到结果：<code>5709294</code></p><p>三次执行的时间分别是：<code>5903</code>,<code>5323</code>,<code>8401</code></p><h2 id="一般分页查询"><a href="#一般分页查询" class="headerlink" title="一般分页查询"></a>一般分页查询</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> <span class="keyword">table</span> LIMIT [<span class="keyword">offset</span>,] <span class="keyword">rows</span> <span class="operator">|</span> <span class="keyword">rows</span> <span class="keyword">OFFSET</span> <span class="keyword">offset</span></span><br></pre></td></tr></table></figure><p>LIMIT子句可以被用于指定 SELECT 语句返回的记录数。需注意以下几点：</p><ul><li>第一个参数指定第一个返回记录行的偏移量</li><li>第二个参数指定返回记录行的最大数目</li><li>如果只给定一个参数：它表示返回最大的记录行数目</li><li>第二个参数为 -1 表示检索从某一个偏移量到记录集的结束所有的记录行</li><li>初始记录行的偏移量是0(而不是 1)</li></ul><p>我们进行一个简单的测试</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> order_history <span class="keyword">WHERE</span> type <span class="operator">=</span> <span class="number">8</span> LIMIT <span class="number">1000</span>,<span class="number">10</span>;</span><br></pre></td></tr></table></figure><p>这个语句就是表示获取第1000条数据开始，后面的十条数据。</p><p>执行三次，查询时间如下：</p><ul><li>3040 ms</li><li>3063 ms</li><li>3018 ms</li></ul><p>使用这样的模式，我们运行下面的语句（偏移量相同，数据量不同）</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">10000</span>,<span class="number">1</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">10000</span>,<span class="number">10</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">10000</span>,<span class="number">100</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">10000</span>,<span class="number">1000</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">10000</span>,<span class="number">10000</span>;</span><br></pre></td></tr></table></figure><p>三次查询时间如下：</p><ul><li>查询1条记录：3072ms 3092ms 3002ms</li><li>查询10条记录：3081ms 3077ms 3032ms</li><li>查询100条记录：3118ms 3200ms 3128ms</li><li>查询1000条记录：3412ms 3468ms 3394ms</li><li>查询10000条记录：3749ms 3802ms 3696ms</li></ul><p>我们可以发现，在查询的数据量比较少的时候，时间基本上没有太多的差距，在数据量比较大的时候，查询时间瞬间飙升。</p><p>我们再运行下面的语句（偏移量不同，数据量相同）</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">100</span>,<span class="number">100</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">1000</span>,<span class="number">100</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">10000</span>,<span class="number">100</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">100000</span>,<span class="number">100</span>;</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">1000000</span>,<span class="number">100</span>;</span><br></pre></td></tr></table></figure><p>三次查询时间如下：</p><ul><li>查询100偏移：25ms 24ms 24ms</li><li>查询1000偏移：78ms 76ms 77ms</li><li>查询10000偏移：3092ms 3212ms 3128ms</li><li>查询100000偏移：3878ms 3812ms 3798ms</li><li>查询1000000偏移：14608ms 14062ms 14700ms</li></ul><p>随着查询偏移的增大，尤其查询偏移大于10万以后，查询时间急剧增加。</p><p><strong>这种分页查询方式会从数据库第一条记录开始扫描，所以越往后，查询速度越慢，而且查询的数据越多，也会拖慢总查询速度。</strong></p><h2 id="使用子查询优化"><a href="#使用子查询优化" class="headerlink" title="使用子查询优化"></a>使用子查询优化</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">100000</span>,<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> id <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">100000</span>,<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> <span class="keyword">and</span> id <span class="operator">&gt;=</span> </span><br><span class="line">(<span class="keyword">select</span> id <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">100000</span>,<span class="number">1</span>) limit <span class="number">100</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">8</span> limit <span class="number">100000</span>,<span class="number">100</span>;</span><br></pre></td></tr></table></figure><p>4条语句的查询时间如下：</p><ul><li>第1条语句：3674ms</li><li>第2条语句：1315ms</li><li>第3条语句：1327ms</li><li>第4条语句：3710ms</li></ul><p>针对上面的查询需要注意：</p><ul><li>比较第1条语句和第2条语句：使用 select id 代替 select * 速度增加了3倍</li><li>比较第2条语句和第3条语句：速度相差几十毫秒</li><li>比较第3条语句和第4条语句：得益于 select id 速度增加，第3条语句查询速度增加了3倍</li></ul><p>这种方式相较于原始一般的查询方法，将会增快数倍。</p><h2 id="使用ID进行限定优化"><a href="#使用ID进行限定优化" class="headerlink" title="使用ID进行限定优化"></a>使用ID进行限定优化</h2><p>这种方式假设数据表的id是<strong>连续递增</strong>的，则我们根据查询的页数和查询的记录数可以算出查询的id的范围，可以使用 id between and 来查询：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> type<span class="operator">=</span><span class="number">2</span> </span><br><span class="line"><span class="keyword">and</span> id <span class="keyword">between</span> <span class="number">1000000</span> <span class="keyword">and</span> <span class="number">1000100</span> limit <span class="number">100</span>;</span><br></pre></td></tr></table></figure><p>查询时间：15ms 12ms 9ms</p><p>这种查询方式能够极大地优化查询速度，基本能够在几十毫秒之内完成。限制是只能使用于明确知道id的情况，不过一般建立表的时候，都会添加基本的id字段，这为分页查询带来很多便利。</p><p>还可以有另外一种写法：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> orders_history <span class="keyword">where</span> id <span class="operator">&gt;=</span> <span class="number">1000001</span> limit <span class="number">100</span>;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;当需要从数据库查询的表有上万条记录的时候，一次性查询所有结果会变得很慢，特别是随着数据量的增加特别明显，这时需要使用分页查询。对于数据库分页查询，也有很多种方法和优化的点。下面简单说一下我知道的一些方法。&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="MySQL" scheme="https://www.ripic.site/tags/MySQL/"/>
    
  </entry>
  
  <entry>
    <title>有关『老了』</title>
    <link href="https://www.ripic.site/archives/2022/09/05/about-me-being-old.html"/>
    <id>https://www.ripic.site/archives/2022/09/05/about-me-being-old.html</id>
    <published>2022-09-05T19:49:56.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<div class="tag-plugin note" ><div class="title">引自知乎</div><div class="body"><p>貌似很多十多或二十出头的年轻人都喜欢说自己老了，一句话包含了很多意思，希望每个年纪轻轻就说“我老了”这种话的人是真的有经历和岁月给予的成熟和成就，肚子里真的“有货”，可以带给他人真正有价值的引导或经验之谈，而不是仅仅满足心理的渴望被认可的成熟和无来由的优越感。越是成熟的稻穗，越懂得弯腰。 <br><br> 作者：<a href="https://www.zhihu.com/question/266835557/answer/1065714268">李思颖 &#x2F; 知乎 (有删节)</a></p></div></div><p>最近在做错事情，更确切地说是在做不到某些事情的时候经常会抱怨自己老了，今天细细一想，又觉得有诸多的不妥，年纪轻轻就以这种方式自嘲，可悲倒是谈不上，只是觉得有一点别扭。</p><p>首先，老了表达出自己这点小事都没做好，有一点悲哀，有一点可笑，表示出自己的能力<strong>不如从前</strong>，很多曾经能做到的事情现如今做不到了，在外人面前没办法找的借口。</p><p>深入分析过后，发现这是一种很可怕的行为。从年轻到老是一个循序渐进的过程，这个 老了也暗含了我曾经能做到，现在不需要或者因为遗忘才做不到这件事，一定程度上有一点满足内心无来由的优越感，同时也有一点讥讽他人突出自己经历的多的意思。</p><div class="tag-plugin note" color="blue"><div class="body"><p>谎言说一百次，就会变成真实；自嘲说一百次，就会变成暗示。</p></div></div><p>成熟并不等于老了，所谓的老了，更多的是对年轻时的总结，以及对过去事物的沉醉。可现在的年轻人又怎能一味回味过去的成绩，而忘记了为未来拼搏呢？我相信，年轻人与老年人的最大区别就是年轻人更加率直、更有活力、遇事不妥协喜欢迎难而上。相较于『老了』这种生活状态或生活态度，年轻人更加愿意去尝试新鲜的事物。</p><p>闲暇时光到操场打一场羽毛球、心烦意乱出门跑到大汗淋漓、遇到事情敢做感言不想着退缩，我想这才是年轻人应该有的模样吧！</p><p>知乎曾经有这样的一个问题：“这一代年轻人，还有不计生死的血性吗？”。</p><p>现如今这个问题也留给了我，虽然说目前无需考虑“不计生死”的问题，但是也应在老气横秋和年少热血中间做一个选择了！</p>]]></content>
    
    
    <summary type="html">最近在做错事情，更确切地说是在做不到某些事情的时候经常会抱怨自己老了，今天细细一想，又觉得有诸多的不妥，年纪轻轻就以这种方式自嘲，可悲倒是谈不上，只是觉得有一点别扭。</summary>
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
    <category term="老了" scheme="https://www.ripic.site/tags/%E8%80%81%E4%BA%86/"/>
    
  </entry>
  
  <entry>
    <title>Leetcode 1011：在 D 天内送达包裹的能力</title>
    <link href="https://www.ripic.site/archives/2022/08/28/leetcode-1011.html"/>
    <id>https://www.ripic.site/archives/2022/08/28/leetcode-1011.html</id>
    <published>2022-08-28T12:25:10.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>题目： <a href="https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/">在 D 天内送达包裹的能力</a></p><span id="more"></span><p>难度：Middle</p><p>知识点：双指针、二分法</p><p>咋说呢，这种有范围可以逆向考虑的题目还是得用二分法逐一验证啊！多说无益，全是套路，记住这种出现范围和可验证的条件吧！</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//执行耗时:9 ms,击败了97.62% 的Java用户</span></span><br><span class="line"><span class="comment">//内存消耗:45.3 MB,击败了12.84% 的Java用户</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">shipWithinDays</span><span class="params">(<span class="type">int</span>[] weights, <span class="type">int</span> days)</span> &#123;</span><br><span class="line">        <span class="comment">// 确定二分查找左右边界</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">left</span> <span class="operator">=</span> Integer.MIN_VALUE;</span><br><span class="line">        <span class="type">int</span> <span class="variable">right</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> weight : weights) &#123;</span><br><span class="line">            left = Math.max(weight, left);</span><br><span class="line">            right += weight;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span> (left &lt; right) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">mid</span> <span class="operator">=</span> (left + right) / <span class="number">2</span>;</span><br><span class="line">            <span class="comment">// need 为需要运送的天数</span></span><br><span class="line">            <span class="comment">// cur 为当前这一天已经运送的包裹重量之和</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">need</span> <span class="operator">=</span> <span class="number">1</span>, cur = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> weight : weights) &#123;</span><br><span class="line">                <span class="comment">//这个地方注意判断条件</span></span><br><span class="line">                <span class="keyword">if</span> (cur + weight &gt; mid) &#123;</span><br><span class="line">                    ++need;</span><br><span class="line">                    cur = <span class="number">0</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                cur += weight;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (need &lt;= days) &#123;</span><br><span class="line">                right = mid;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">//mid不应该被包含进来</span></span><br><span class="line">                left = mid + <span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> left;</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>LC875 LC1231</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;题目： &lt;a href=&quot;https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/&quot;&gt;在 D 天内送达包裹的能力&lt;/a&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Leetcode" scheme="https://www.ripic.site/categories/Leetcode/"/>
    
    
    <category term="Leetcode" scheme="https://www.ripic.site/tags/Leetcode/"/>
    
  </entry>
  
  <entry>
    <title>Leetcode 10：正则表达式匹配</title>
    <link href="https://www.ripic.site/archives/2022/08/28/leetcode-10.html"/>
    <id>https://www.ripic.site/archives/2022/08/28/leetcode-10.html</id>
    <published>2022-08-28T12:24:10.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>题目： <a href="https://leetcode.cn/problems/regular-expression-matching/">正则表达式匹配</a></p><span id="more"></span><p>难度：Hard</p><p>知识点：动态规划、递归</p><p>按照1xx、2xx的顺序做题，然后发现10也是一个值得记录一下的题目，于是写一下吧。</p><p><del>首先说明一点的是，leetcode官方给出的答案属实是没看懂，我还是自己写一下吧</del></p><p>终于看懂官方的答案了，并且自己写了出来，详见解法2。</p><h3 id="解法1"><a href="#解法1" class="headerlink" title="解法1"></a>解法1</h3><p>看到这个题目，第一感觉很难想到官解的动态规划思路，感觉递归才是人之常情，这里就先写一下递归的操作吧，当然，下面的递归算不上是最好的算法，同时可以增加dp消除重复字问题。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//执行耗时:14 ms,击败了16.27% 的Java用户</span></span><br><span class="line"><span class="comment">//内存消耗:39.8 MB,击败了81.81% 的Java用户</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="type">char</span>[] arrs;</span><br><span class="line">    <span class="type">char</span>[] arrp;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isMatch</span><span class="params">(String s, String p)</span> &#123;</span><br><span class="line">        arrs = s.toCharArray();</span><br><span class="line">        arrp = p.toCharArray();</span><br><span class="line">        <span class="keyword">return</span> dp(<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">dp</span><span class="params">(<span class="type">int</span> indexS, <span class="type">int</span> indexP)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> arrs.length;</span><br><span class="line">        <span class="type">int</span> <span class="variable">n</span> <span class="operator">=</span> arrp.length;</span><br><span class="line">        <span class="comment">//base case</span></span><br><span class="line">        <span class="keyword">if</span> (indexP == n) <span class="keyword">return</span> indexS == m;</span><br><span class="line">        <span class="keyword">if</span> (indexS == m) &#123;</span><br><span class="line">            <span class="comment">//判断剩余元素是否为奇数</span></span><br><span class="line">            <span class="keyword">if</span> ((n - indexP) % <span class="number">2</span> == <span class="number">1</span>) &#123;</span><br><span class="line">                <span class="comment">//如果剩余元素是奇数，那么直接就不能够完全消除掉</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">for</span> (; indexP + <span class="number">1</span> &lt; n; indexP = indexP + <span class="number">2</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (arrp[indexP + <span class="number">1</span>] != <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//开始递归操作</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">res</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="comment">//如果当前位置匹配</span></span><br><span class="line">        <span class="keyword">if</span> (arrs[indexS] == arrp[indexP] || arrp[indexP] == <span class="string">&#x27;.&#x27;</span>) &#123;</span><br><span class="line">            <span class="comment">//如果下一位是*，name我们要考虑用不用掉这个*</span></span><br><span class="line">            <span class="keyword">if</span> (indexP &lt; n - <span class="number">1</span> &amp;&amp; arrp[indexP + <span class="number">1</span>] == <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">                <span class="comment">// 这个*代表匹配indexP的元素0次（indexP+1是*，跳过</span></span><br><span class="line">                <span class="comment">// 第二种情况代表着匹配多次，也就是说indexS递增，indexP不变</span></span><br><span class="line">                res = dp(indexS,indexP+<span class="number">2</span>) ||</span><br><span class="line">                        dp(indexS+<span class="number">1</span>,indexP);</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                res = dp(indexS+<span class="number">1</span>,indexP+<span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//如果当前位置不匹配，那么就只能消耗掉（字母*）</span></span><br><span class="line">            <span class="keyword">if</span> (indexP &lt; n - <span class="number">1</span> &amp;&amp; arrp[indexP + <span class="number">1</span>] == <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">                res = dp(indexS, indexP + <span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                res = <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</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></pre></td></tr></table></figure><h3 id="解法2"><a href="#解法2" class="headerlink" title="解法2"></a>解法2</h3><p>还是需要研究一下官方的解决方法，这里做一个简单的记录吧</p><p>几个注意的点：</p><ul><li>s字符串需要有前0位（空）的情况，因为前0位可以和特殊的前两位（a*）进行匹配，不能忽略递归结构</li><li>dp中的编号与字符串的index要区分开！！！</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//执行耗时:1 ms,击败了99.97% 的Java用户</span></span><br><span class="line"><span class="comment">//内存消耗:39.9 MB,击败了77.69% 的Java用户</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="type">char</span>[] arrs;</span><br><span class="line">    <span class="type">char</span>[] arrp;</span><br><span class="line">    <span class="type">boolean</span>[][] ans;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isMatch</span><span class="params">(String s, String p)</span> &#123;</span><br><span class="line">        arrs = s.toCharArray();</span><br><span class="line">        arrp = p.toCharArray();</span><br><span class="line">        ans = <span class="keyword">new</span> <span class="title class_">boolean</span>[s.length() + <span class="number">1</span>][p.length() + <span class="number">1</span>];</span><br><span class="line">        <span class="comment">//默认情况应该是dp[0][0] = true;</span></span><br><span class="line">        ans[<span class="number">0</span>][<span class="number">0</span>] = <span class="literal">true</span>;</span><br><span class="line">        dp();</span><br><span class="line">        <span class="keyword">return</span> ans[arrs.length][arrp.length];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">dp</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">indexS</span> <span class="operator">=</span> <span class="number">0</span>; indexS &lt;= arrs.length; indexS++) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">indexP</span> <span class="operator">=</span> <span class="number">1</span>; indexP &lt;= arrp.length; indexP++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (arrp[indexP - <span class="number">1</span>] != <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">                    <span class="comment">//这一位不是*，这一位可以靠自己</span></span><br><span class="line">                    <span class="keyword">if</span> (check(indexS - <span class="number">1</span>, indexP - <span class="number">1</span>)) &#123;</span><br><span class="line">                        ans[indexS][indexP] = ans[indexS - <span class="number">1</span>][indexP - <span class="number">1</span>];</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">/**</span></span><br><span class="line"><span class="comment">                     * 第indexP位是*</span></span><br><span class="line"><span class="comment">                     * arrp[indexP-1]是*</span></span><br><span class="line"><span class="comment">                     * arrp[indexP-2]是可以被消掉的</span></span><br><span class="line"><span class="comment">                     * 匹配多次的是arrp[indexP-2]</span></span><br><span class="line"><span class="comment">                     */</span></span><br><span class="line">                    <span class="keyword">if</span> (indexP &gt;= <span class="number">2</span>)</span><br><span class="line">                        <span class="comment">//相当于向前缩了两位，在编号上-2即可</span></span><br><span class="line">                        ans[indexS][indexP] = ans[indexS][indexP - <span class="number">2</span>];</span><br><span class="line">                    <span class="comment">//匹配多次的情况，检查当前字符和*前面的字符是否一致，一致才有下文</span></span><br><span class="line">                    <span class="keyword">if</span> (check(indexS - <span class="number">1</span>, indexP - <span class="number">2</span>)) &#123;</span><br><span class="line">                        <span class="comment">//如果一致，还要考虑前一位和当前的匹配关系，前一位可能是匹配0次，也可能是匹配一次，需要推倒回去，这也是很多情况的一个压缩！！！</span></span><br><span class="line"><span class="comment">//①只需要匹配1次：if保证了匹配，递归一次变匹配0次</span></span><br><span class="line"><span class="comment">//②匹配多次，我们削减待匹配的字符串，直到0次</span></span><br><span class="line">                        ans[indexS][indexP] = ans[indexS - <span class="number">1</span>][indexP] || ans[indexS][indexP];</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">check</span><span class="params">(<span class="type">int</span> indexS, <span class="type">int</span> indexP)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (indexS == -<span class="number">1</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="keyword">if</span> (arrp[indexP] == <span class="string">&#x27;.&#x27;</span> || arrp[indexP] == arrs[indexS]) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>很佩服出题人，也佩服能想到这种解法的人！</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//执行耗时:33 ms,击败了9.81% 的Java用户 </span></span><br><span class="line"><span class="comment">//内存消耗:42 MB,击败了5.03% 的Java用户</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isMatch</span><span class="params">(String s, String p)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> s.matches(p);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>大大的鄙视！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;题目： &lt;a href=&quot;https://leetcode.cn/problems/regular-expression-matching/&quot;&gt;正则表达式匹配&lt;/a&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Leetcode" scheme="https://www.ripic.site/categories/Leetcode/"/>
    
    
    <category term="Leetcode" scheme="https://www.ripic.site/tags/Leetcode/"/>
    
  </entry>
  
  <entry>
    <title>Leetcode 1：两数之和</title>
    <link href="https://www.ripic.site/archives/2022/08/28/leetcode-1.html"/>
    <id>https://www.ripic.site/archives/2022/08/28/leetcode-1.html</id>
    <published>2022-08-28T11:56:11.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>题目：<a href="https://leetcode.cn/problems/two-sum/">两数之和</a></p><span id="more"></span><p>难度：easy</p><p>知识点：暴力、哈希表</p><p>俗话说，万事开头难，第一道题当然是要写一下leetcode的第一题啊！</p><h3 id="解法1"><a href="#解法1" class="headerlink" title="解法1"></a>解法1</h3><p>很容易想到的有个方法就是暴力解决，也很简单，不断地遍历，时间复杂度为O(n^2)，直接上代码吧。</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">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span>[] twoSum(<span class="type">int</span>[] nums, <span class="type">int</span> target) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> i + <span class="number">1</span>; j &lt; nums.length; j++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(nums[i] + nums[j] == target)&#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">int</span>[]&#123;i,j&#125;;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="解法2"><a href="#解法2" class="headerlink" title="解法2"></a>解法2</h3><p>我们可以增加一个备忘录的功能，一旦发现备忘录中存在我们正在找的元素，那么直接返回即可。</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">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span>[] twoSum(<span class="type">int</span>[] nums, <span class="type">int</span> target) &#123;</span><br><span class="line">        Map&lt;Integer, Integer&gt; hashtable = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;Integer, Integer&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; nums.length; ++i) &#123;</span><br><span class="line">            <span class="keyword">if</span> (hashtable.containsKey(nums[i])) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">int</span>[]&#123;hashtable.get(nums[i]), i&#125;;</span><br><span class="line">            &#125;</span><br><span class="line">            hashtable.put(target - nums[i], i);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">int</span>[<span class="number">0</span>];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>以上就是两种不同的方法了。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;题目：&lt;a href=&quot;https://leetcode.cn/problems/two-sum/&quot;&gt;两数之和&lt;/a&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Leetcode" scheme="https://www.ripic.site/categories/Leetcode/"/>
    
    
    <category term="Leetcode" scheme="https://www.ripic.site/tags/Leetcode/"/>
    
  </entry>
  
  <entry>
    <title>最后一公里的思考</title>
    <link href="https://www.ripic.site/archives/2022/08/13/Last-Mile-Thoughts.html"/>
    <id>https://www.ripic.site/archives/2022/08/13/Last-Mile-Thoughts.html</id>
    <published>2022-08-13T17:55:03.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>在我看来，中国的互联网投资人有个很奇怪的现象，他们总是要解决所谓“最后一公里”的问题。可能是快递外卖等服务行业在最后一公里上过于成功，互联网创业者们也始终觉得所有的服务和商业最终总是要直接上门的，所以他们搞出来O2O，让你可以在线按摩美甲；他们搞出来共享单车，让你可以从车站直接骑到小区门口；他们还搞出生鲜电商，让你从此告别菜场和超市。在他们的观念里，所有普通的生活都被互联网改造，就算是改变世界了。</p><p>但是，我们是否真的处处需要互联网这个事情，我觉得是要打个问号的，从来没有人问过我们，最后一公里需不需要被改造。这一公里是什么，是我步行回家时的招猫逗狗，是遛弯时意外地落日夕阳；是广场上小孩子的嬉笑打闹，是夏日里老人纳凉的蒲扇，是菜场摊位老板顺手送我们的一把小葱，是晚饭后逛逛超市的悠闲自在。这一公里就是我们与无孔不入的现代性的距离，是真实世界与赛博世界的护城河。人需要便利，世界也需要效率，但那些不方便的地方，才更多的保留了原本的我们，保留了更多的人性。所谓人的生活，不就是可以在方便的时候选择那些不方便的生活方式吗？</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在我看来，中国的互联网投资人有个很奇怪的现象，他们总是要解决所谓“最后一公里”的问题。可能是快递外卖等服务行业在最后一公里上过于成功，互联网创业者们也始终觉得所有的服务和商业最终总是要直接上门的，所以他们搞出来O2O，让你可以在线按摩美甲；他们搞出来共享单车，让你可以从车站</summary>
      
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
  </entry>
  
  <entry>
    <title>英雄联盟语录</title>
    <link href="https://www.ripic.site/archives/2022/06/04/league-of-legends-quotes.html"/>
    <id>https://www.ripic.site/archives/2022/06/04/league-of-legends-quotes.html</id>
    <published>2022-06-04T22:11:18.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<div class="tag-plugin link dis-select"><a class="link-card plain" title="" href="https://y.qq.com/n/ryqq/songDetail/002FxM7f0Ze1az" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="title,icon"><div class="left"><span class="title">https://y.qq.com/n/ryqq/songDetail/002FxM7f0Ze1az</span><span class="cap link fs12">https://y.qq.com/n/ryqq/songDetail/002FxM7f0Ze1az</span></div><div class="right"><div class="lazy img" data-bg="https://jsdelivr-mirror.ripic.site/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div><ul><li><strong>时间不在于你拥有多少，而在于你怎样使用；</strong></li><li><strong>时间不能治愈所有伤口。</strong></li><li><strong>怀疑是最强大的敌人；</strong></li><li><strong>不要被骄傲遮蔽了双眼，愤怒带来冲动！</strong></li><li><strong>行事先于蛮力，绝对不要坐等胜利的到来！</strong></li><li><strong>集中起来的意志可以击穿顽石；</strong></li><li><strong>好好看，好好学，真正的大师永远都怀着一颗学徒的心；</strong></li><li><strong>回首往昔，更进一步；</strong></li><li><strong>荣耀存于心，而非留于行；</strong></li><li><strong>攀登的过程也许漫长，但巅峰的风景是值得的；</strong></li><li><strong>我曾踏足山巅也曾进入低谷，二者都让我受益良多；</strong></li><li><strong>累得直不起腰来才是生命中最大的快乐；</strong></li><li><strong>有的时候你只需要做你自己；</strong></li><li><strong>当我受到了排挤的时候，你和我站一边，所以你喝醉的时候我也会站在你那边，即使你臭气熏天；</strong></li><li><strong>一只手放在了天平上，哪里还会有什么真正的平衡；</strong></li><li><strong>我们每个人的心里都有一道被重重迷雾包裹的谜题；</strong></li><li><strong>评判他人就等于谴责自己；</strong></li><li><strong>眼中的世界要只有黑与白，就会错失生命中所有颜色；</strong></li><li><strong>如果你没有战斗的本领，起码也要有赴死的意识！</strong></li><li><strong>你得先看中你自己，否则别人就会当你一文不值；</strong></li><li><strong>成功与失败的分别在于适应能力的高低；</strong></li><li><strong>如果生活还没能改变你，那你已经失败了；</strong></li><li><strong>定义你的不是武器本身，而是你使用它的方式；</strong></li><li><strong>灵活的剑术可以赢的一时，但灵活的头脑才能赢一世；</strong></li><li><strong>自负会让每个人都屈膝下跪，机会只会眷顾等待的人；</strong></li><li><strong>耐心不是一种品德，而是唯一的品德！</strong></li><li><strong>有时候伤疤是一个人最上等的华服。</strong></li></ul>]]></content>
    
    
    <summary type="html">英雄联盟励志语录 - QQ音乐</summary>
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
    <category term="英雄联盟" scheme="https://www.ripic.site/tags/%E8%8B%B1%E9%9B%84%E8%81%94%E7%9B%9F/"/>
    
  </entry>
  
  <entry>
    <title>生活的一点感悟</title>
    <link href="https://www.ripic.site/archives/2022/06/04/a-little-insight-into-life.html"/>
    <id>https://www.ripic.site/archives/2022/06/04/a-little-insight-into-life.html</id>
    <published>2022-06-04T21:45:21.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<h3 id="零"><a href="#零" class="headerlink" title="零"></a>零</h3><p>最近在和一位在某大厂工作的的学姐一起交流有关开发的相关问题，原本以为只是Coding一些代码，调用一些接口写个数据库就结束了，很清晰，也很简单。没想到关于开发，关于学习，关于就业这些有的没的足足聊了三个半小时（3小时31分8秒），感触颇深吧！</p><h3 id="壹"><a href="#壹" class="headerlink" title="壹"></a>壹</h3><p>我向来是一个“心气”颇高的人，不单单是对自己的发展、薪水这些正向的东西；对一些租房、通勤、日常开销这些反向的东西也颇为“积极”。导致经常会出现入不敷出或者是留不住钱的情况。即使短短15分钟不到的路程可能也更加偏爱打车（一般在7元左右），虽然不是常常出游（以后可能就更少出游了，毕竟同行者不见了啊），但也算是一笔不小的负担了。</p><p>和学姐聊天之余，使得（姑且认为是“使得”吧）她错过了回家的公交车，被逼无奈之下选择了打车回家。觉得学姐对打车这件事决定的十分慎重，完全没有我那种或是碍于面子，或是少量思考就决定下来的鲁莽。事后我开始调侃说“不当家不知柴米油盐贵”之类的话，可是，细细想来又何尝不是如此呢？</p><p>不同平台开通会员，每每想做一件事就会不计成本的投入，到最后不论是金钱还是经历都变成了“沉没成本”，只能依稀记得当年下定决心时的涟漪，多少来说，是有些可笑的。</p><p>上面的话就已经对我目前锁经历的事情进行了升华，不论是金钱还是经历，都要考虑好值不值得在这里进行花销，金钱是自己的物质基础，经历是自己的精神基础，某种意义上他们都是一个人不可或缺的两种资源吧，都具有一定的共同之处。</p><h3 id="贰"><a href="#贰" class="headerlink" title="贰"></a>贰</h3><p>曾经找过心理医生诊断过（再用一个姑且吧，与其说诊断，不如说测试更为恰切），最终的结论说我的性格有点偏向“外向式孤独”，也就是说吧乐观开朗的一面展现给别人，把孤独自卑的一面留给自己，可能会一个人独自内耗，喜欢被关注的感觉，又讨厌被过度关注（哈哈，贱人就是矫情~）。仔细想来，这也是在大手大脚地“花费”着自己的精力，丝毫不顾忌这些精力是否用在了正确的场合和事情上，最终导致过多的精力留给了外面，自己的内心世界却不充实，独自一人承受悲伤。</p><p>最近，我也发生了很多的变故吧，不断的emo，然后自愈，再emo，再自愈，这个道理也在慢慢地加深，但是有的时候真的不知道这种想法到底对不对，暂且边看边学吧。</p><h3 id="叁"><a href="#叁" class="headerlink" title="叁"></a>叁</h3><p>当我受到排挤的时候你和我站在一边，所以当你喝醉的时候我也会站在你那边，即使你臭气熏天。</p><p>一只手放在天平上，哪还有真正的平衡。</p><p>就胡言乱语这么多吧！</p>]]></content>
    
    
    <summary type="html">胡言乱语罢了</summary>
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
    <category term="感悟" scheme="https://www.ripic.site/tags/%E6%84%9F%E6%82%9F/"/>
    
  </entry>
  
  <entry>
    <title>不负此生</title>
    <link href="https://www.ripic.site/archives/2022/05/25/bilibili-live-up-to-this-life.html"/>
    <id>https://www.ripic.site/archives/2022/05/25/bilibili-live-up-to-this-life.html</id>
    <published>2022-05-25T23:39:37.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<h3 id="人生应该活成什么样子？这是我听到过最好的答案！"><a href="#人生应该活成什么样子？这是我听到过最好的答案！" class="headerlink" title="人生应该活成什么样子？这是我听到过最好的答案！"></a>人生应该活成什么样子？这是我听到过最好的答案！</h3><span id="more"></span><p>【原创短片】辞掉国企工作去翼装飞行，大学生村官顶着村民的不信任一呆就是好几年，放弃国外高待遇回国做研究……..到底怎么样的一生才是有意义的？三位主人公用行动告诉我们：在自己认定的事情上坚定不移的付出，这大概就是最好的人生。</p><div class="tag-plugin link dis-select"><a class="link-card rich" title="" href="https://www.bilibili.com/video/BV1kt411R7a3" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="title,icon,desc"><div class="top"><div class="lazy img" data-bg="https://jsdelivr-mirror.ripic.site/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div><span class="cap link fs12">https://www.bilibili.com/video/BV1kt411R7a3</span></div><div class="bottom"><span class="title">https://www.bilibili.com/video/BV1kt411R7a3</span><span class="cap desc fs12"></span></div></a></div>]]></content>
    
    
    <summary type="html">&lt;h3 id=&quot;人生应该活成什么样子？这是我听到过最好的答案！&quot;&gt;&lt;a href=&quot;#人生应该活成什么样子？这是我听到过最好的答案！&quot; class=&quot;headerlink&quot; title=&quot;人生应该活成什么样子？这是我听到过最好的答案！&quot;&gt;&lt;/a&gt;人生应该活成什么样子？这是我听到过最好的答案！&lt;/h3&gt;</summary>
    
    
    
    <category term="闲言" scheme="https://www.ripic.site/categories/%E9%97%B2%E8%A8%80/"/>
    
    
  </entry>
  
  <entry>
    <title>小程序支付代码实现</title>
    <link href="https://www.ripic.site/archives/2022/05/21/how-to-execute-a-wechat-miniprogram-pay.html"/>
    <id>https://www.ripic.site/archives/2022/05/21/how-to-execute-a-wechat-miniprogram-pay.html</id>
    <published>2022-05-21T20:55:38.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>这里只是写一下小程序相关的js代码吧，wxss和wxml代码就自行调试吧</p><span id="more"></span><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app.js</span></span><br><span class="line"><span class="title class_">App</span>(&#123;</span><br><span class="line">  <span class="attr">globalData</span>: &#123;</span><br><span class="line">    <span class="attr">openid</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">payapiUrl</span>:<span class="string">&#x27;https://pay-api.example.com&#x27;</span>,</span><br><span class="line">    <span class="attr">wxapiUrl</span>:<span class="string">&#x27;https://wx-api.example.com&#x27;</span></span><br><span class="line"></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">onLaunch</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">globalData</span>)</span><br><span class="line">    <span class="keyword">var</span> _this =<span class="variable language_">this</span>;</span><br><span class="line">    <span class="comment">// 登录</span></span><br><span class="line">    wx.<span class="title function_">login</span>(&#123;</span><br><span class="line">      <span class="attr">success</span>: <span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">       <span class="comment">//console.log(res.code)</span></span><br><span class="line">       wx.<span class="title function_">request</span>(&#123;</span><br><span class="line">         <span class="attr">url</span>: <span class="variable language_">this</span>.<span class="property">globalData</span>.<span class="property">wxapiUrl</span> + <span class="string">&#x27;/login&#x27;</span>,</span><br><span class="line">         <span class="attr">method</span>:<span class="string">&quot;POST&quot;</span>,</span><br><span class="line">         <span class="attr">data</span>:&#123;</span><br><span class="line">           <span class="attr">code</span>:res.<span class="property">code</span></span><br><span class="line">         &#125;,</span><br><span class="line">         <span class="attr">dataType</span>:<span class="string">&quot;json&quot;</span>,</span><br><span class="line">         <span class="attr">header</span>: &#123;</span><br><span class="line">           <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/x-www-form-urlencoded&quot;</span>  </span><br><span class="line">          &#125;</span><br><span class="line">         ,<span class="attr">success</span>:<span class="keyword">function</span>(<span class="params">result</span>)&#123;</span><br><span class="line">          <span class="comment">//  console.log(result.data.openid)</span></span><br><span class="line">           _this.<span class="property">globalData</span>.<span class="property">openid</span> = result.<span class="property">data</span>.<span class="property">openid</span></span><br><span class="line">         &#125;</span><br><span class="line">       &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// pages/orderPay/orderPay.js</span></span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">getApp</span>();</span><br><span class="line"><span class="title class_">Page</span>(&#123;</span><br><span class="line">    <span class="attr">data</span>: &#123;</span><br><span class="line">        <span class="attr">orderNo</span>:<span class="string">&quot;&quot;</span>,</span><br><span class="line"><span class="attr">payMoney</span>:<span class="string">&quot;&quot;</span>,</span><br><span class="line"><span class="attr">name</span>:<span class="string">&quot;&quot;</span>,</span><br><span class="line"><span class="attr">merchant</span>:<span class="string">&quot;&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">onLoad</span>: <span class="keyword">function</span> (<span class="params">options</span>) &#123;</span><br><span class="line"><span class="keyword">if</span>(options.<span class="property">q</span>)&#123; </span><br><span class="line">            <span class="keyword">var</span> _this=<span class="variable language_">this</span>;</span><br><span class="line">            <span class="keyword">var</span> link = <span class="built_in">decodeURIComponent</span>(options.<span class="property">q</span>);</span><br><span class="line">            <span class="keyword">var</span> paramArr = link.<span class="title function_">split</span>(<span class="string">&#x27;=&#x27;</span>);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">setData</span>(&#123;</span><br><span class="line">                <span class="attr">orderNo</span>:paramArr[<span class="number">1</span>]</span><br><span class="line">            &#125;)</span><br><span class="line">            wx.<span class="title function_">request</span>(&#123;</span><br><span class="line">              <span class="attr">url</span>: app.<span class="property">globalData</span>.<span class="property">apiUrl</span> + <span class="string">&#x27;/order/getinfo&#x27;</span>,</span><br><span class="line">              <span class="attr">data</span>:&#123;</span><br><span class="line">                  <span class="attr">id</span>:paramArr[<span class="number">1</span>]</span><br><span class="line">              &#125;,</span><br><span class="line">              <span class="attr">success</span>:<span class="keyword">function</span>(<span class="params">e</span>)&#123;</span><br><span class="line">                  <span class="variable language_">console</span>.<span class="title function_">log</span>(e.<span class="property">data</span>)</span><br><span class="line">                  <span class="keyword">if</span>(!e.<span class="property">data</span>.<span class="property">amt</span>)&#123;</span><br><span class="line">                      wx.<span class="title function_">redirectTo</span>(&#123;</span><br><span class="line">                        <span class="attr">url</span>: <span class="string">&#x27;/pages/info/error&#x27;</span>,</span><br><span class="line">                      &#125;)</span><br><span class="line">                      <span class="keyword">return</span>;</span><br><span class="line">                  &#125;</span><br><span class="line">  <span class="comment">//订单状态为已经支付或者已经扫码</span></span><br><span class="line">  <span class="comment">//<span class="doctag">TODO:</span>具体订单报错信息</span></span><br><span class="line">                  <span class="keyword">if</span>(e.<span class="property">data</span>.<span class="property">status</span> != <span class="number">0</span>)&#123;</span><br><span class="line">                      wx.<span class="title function_">redirectTo</span>(&#123;</span><br><span class="line">                        <span class="attr">url</span>: <span class="string">&#x27;/pages/info/error&#x27;</span>,</span><br><span class="line">                      &#125;)</span><br><span class="line">                      <span class="keyword">return</span>;</span><br><span class="line">                  &#125;</span><br><span class="line">                  _this.<span class="title function_">setData</span>(&#123;</span><br><span class="line">                      <span class="attr">payInfo</span>:&#123;</span><br><span class="line"><span class="attr">payMoney</span>:e.<span class="property">data</span>.<span class="property">amt</span>,</span><br><span class="line"><span class="attr">name</span>:e.<span class="property">data</span>.<span class="property">name</span>,</span><br><span class="line"><span class="attr">merchant</span>:e.<span class="property">data</span>.<span class="property">merchant</span></span><br><span class="line">                      &#125;</span><br><span class="line">                  &#125;)</span><br><span class="line">              &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">          &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">              wx.<span class="title function_">redirectTo</span>(&#123;</span><br><span class="line">                <span class="attr">url</span>: <span class="string">&#x27;/pages/info/error&#x27;</span>,</span><br><span class="line">              &#125;)</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">//支付函数</span></span><br><span class="line">    <span class="title function_">handlePay</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> _this = <span class="variable language_">this</span>;</span><br><span class="line">        <span class="keyword">const</span> &#123;</span><br><span class="line">            payMoney</span><br><span class="line">        &#125; = <span class="variable language_">this</span>.<span class="property">data</span></span><br><span class="line">        <span class="keyword">if</span> (payMoney === <span class="string">&#x27;&#x27;</span>|| payMoney ==<span class="number">0</span>) <span class="keyword">return</span></span><br><span class="line">        wx.<span class="title function_">showLoading</span>(&#123;</span><br><span class="line">            <span class="attr">title</span>: <span class="string">&#x27;加载中&#x27;</span>,</span><br><span class="line">        &#125;)</span><br><span class="line">        wx.<span class="title function_">request</span>(&#123;</span><br><span class="line">            <span class="attr">url</span>: app.<span class="property">globalData</span>.<span class="property">apiUrl</span> + <span class="string">&#x27;/newpay/wechatPay&#x27;</span>,</span><br><span class="line">            <span class="attr">dataType</span>: <span class="string">&quot;json&quot;</span>,</span><br><span class="line">            <span class="attr">header</span>: &#123;</span><br><span class="line">                <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/x-www-form-urlencoded&quot;</span></span><br><span class="line">            &#125;,</span><br><span class="line">            <span class="attr">method</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">            <span class="attr">data</span>: &#123;</span><br><span class="line">                <span class="attr">openid</span>: app.<span class="property">globalData</span>.<span class="property">openid</span>,</span><br><span class="line">                <span class="attr">orderNo</span>:_this.<span class="property">data</span>.<span class="property">orderNo</span></span><br><span class="line">                        &#125;,</span><br><span class="line">            <span class="attr">success</span>: <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">                wx.<span class="title function_">hideLoading</span>()</span><br><span class="line">                <span class="keyword">var</span> rst = e.<span class="property">data</span>.<span class="property">data</span>;</span><br><span class="line">                <span class="comment">// var rst = JSON.parse(firstRst);</span></span><br><span class="line">                wx.<span class="title function_">requestPayment</span>(&#123;</span><br><span class="line">                    <span class="attr">timeStamp</span>: rst.<span class="property">timeStamp</span>,</span><br><span class="line">                    <span class="attr">nonceStr</span>: rst.<span class="property">nonceStr</span>,</span><br><span class="line">                    <span class="attr">package</span>: rst.<span class="property">package</span>,</span><br><span class="line">                    <span class="attr">signType</span>: rst.<span class="property">signType</span>,</span><br><span class="line">                    <span class="attr">paySign</span>: rst.<span class="property">paySign</span>,</span><br><span class="line">                    <span class="attr">success</span>: <span class="keyword">function</span> (<span class="params">res</span>) &#123;</span><br><span class="line">                        wx.<span class="title function_">redirectTo</span>(&#123;</span><br><span class="line">                            <span class="attr">url</span>: <span class="string">&#x27;/pages/result/success&#x27;</span>,</span><br><span class="line">                        &#125;)</span><br><span class="line">                        <span class="keyword">return</span>;</span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">fail</span>: <span class="keyword">function</span> (<span class="params">res</span>) &#123;</span><br><span class="line">                        _this.<span class="title function_">setData</span>(&#123;</span><br><span class="line">                            <span class="attr">showNotice</span>: <span class="literal">true</span></span><br><span class="line">                        &#125;)</span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">complete</span>: <span class="keyword">function</span> (<span class="params">res</span>) &#123;&#125;</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;这里只是写一下小程序相关的js代码吧，wxss和wxml代码就自行调试吧&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="小程序" scheme="https://www.ripic.site/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
    <category term="微信支付" scheme="https://www.ripic.site/tags/%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98/"/>
    
  </entry>
  
  <entry>
    <title>聚合支付下单流程</title>
    <link href="https://www.ripic.site/archives/2022/05/21/A-Union-Pay-Process.html"/>
    <id>https://www.ripic.site/archives/2022/05/21/A-Union-Pay-Process.html</id>
    <published>2022-05-21T20:53:11.000Z</published>
    <updated>2023-10-19T09:28:53.444Z</updated>
    
    <content type="html"><![CDATA[<p>最近在写一个聚合支付的系统，支付宝比较好掌控，可是微信支付却有着一大堆的问题亟需解决。</p><h3 id="微信支付"><a href="#微信支付" class="headerlink" title="微信支付"></a>微信支付</h3><p>微信支付除了需要传订单信息，还需要传递当前支付用户的openid，这就导致了我们不能直接通过接口在服务器直接下单，只能自己构建“预下单”接口先在系统中进行预下单，然后在确定当前的支付对象，然后构建H5&#x2F;小程序链接，在H5&#x2F;小程序中获取用户openid，返回给后端进行绑定，然后进行下单支付。</p><p>对于小程序而言，获取用户的openid还是比较方便的，但是难题是怎么将订单信息与用户的openid相关联起来，同时在查询到openid之后要怎么进行下单里调用什么接口，我想这是我现在面临的难题吧！</p><p>于是，我决定把微信支付接口的调用分为以下的几个流程。</p><ul><li>用户下单</li><li>服务器接收订单，返回订单对应的小程序链接</li></ul><blockquote><ul><li>首先验证订单的合法性（API调用凭据、用户金额、支付方式等）</li><li>生成系统订单号</li><li>将系统订单号（由服务端生成）、商户订单号、商品名称等相关信息存入数据库中</li><li>返回带有订单号的小程序链接。</li></ul></blockquote><ul><li>用户扫描小程序码</li></ul><blockquote><ul><li>小程序app.js中首先获取用户的openid，ip等信息，并且存储到小程序的data中</li><li>在orderPay的onload中获取订单号的信息，同时验证该订单是否已经被扫描或者支付过，此时服务端应做好查重处理</li><li>用户点击支付，携带openid，订单号向服务器发起请求，获取支付信息，完成当前支付。</li></ul></blockquote><ul><li>用户支付</li><li>Adapay回调</li><li>回调给客户网站</li></ul><h4 id="支付宝支付"><a href="#支付宝支付" class="headerlink" title="支付宝支付"></a>支付宝支付</h4><p>支付宝支付就相对简单了，我们只需要直接生成支付宝链接传回给前端即可完成支付。</p><h4 id="一码聚合支付"><a href="#一码聚合支付" class="headerlink" title="一码聚合支付"></a>一码聚合支付</h4><p>如果想做一码聚合支付的话，就要考虑到支付宝和微信等浏览器的鉴别问题。</p><p>可行的方法有以下几种：</p><ul><li>借助js完成识别，统统使用H5支付，需要做默认报错页面</li><li>借助小程序绑定域名完成，域名不需要做默认页面</li><li>两者结合</li></ul><p>最终选择的是微信使用小程序域名跳转，支付宝采用H5跳转进行下单，这种方法需要制作非支付宝的默认的支付页面，这里就不再赘述了。</p><h5 id="微信支付的改造"><a href="#微信支付的改造" class="headerlink" title="微信支付的改造"></a>微信支付的改造</h5><p>貌似微信支付不需要进行改造</p><h5 id="支付宝的改造"><a href="#支付宝的改造" class="headerlink" title="支付宝的改造"></a>支付宝的改造</h5><p>这里采取和微信支付相同的策略，在链接中传递orderID，在浏览器识别到支付宝浏览器环境之后，模仿微信支付那样进行下单和其他操作。</p><ul><li>用户下单</li><li>服务器接收订单，返回订单对应的链接</li></ul><blockquote><ul><li>首先验证订单的合法性（API调用凭据、用户金额、支付方式等）</li><li>生成系统订单号</li><li>将系统订单号（由服务端生成）、商户订单号、商品名称等相关信息存入数据库中</li><li>返回带有订单号的链接</li></ul></blockquote><ul><li>用户扫描该链接对应的二维码</li></ul><blockquote><ul><li>浏览器UA判断</li><li>跳转到支付宝对应的页面</li><li>查询对应的订单信息，跳转支付宝支付页面</li></ul></blockquote><ul><li>用户支付</li><li>Adapay回调</li><li>回调给客户网站</li></ul><p>至此，支付流程可以跑的通了！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;最近在写一个聚合支付的系统，支付宝比较好掌控，可是微信支付却有着一大堆的问题亟需解决。&lt;/p&gt;
&lt;h3 id=&quot;微信支付&quot;&gt;&lt;a href=&quot;#微信支付&quot; class=&quot;headerlink&quot; title=&quot;微信支付&quot;&gt;&lt;/a&gt;微信支付&lt;/h3&gt;&lt;p&gt;微信支付除了需要传订单</summary>
      
    
    
    
    <category term="技术" scheme="https://www.ripic.site/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="聚合支付" scheme="https://www.ripic.site/tags/%E8%81%9A%E5%90%88%E6%94%AF%E4%BB%98/"/>
    
    <category term="项目" scheme="https://www.ripic.site/tags/%E9%A1%B9%E7%9B%AE/"/>
    
  </entry>
  
</feed>
