<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>喵先生 的进阶之路</title>
  
  <subtitle>简单  快乐  喵</subtitle>
  <link href="/atom.xml" rel="self"/>
  <link href="%5Bobject%20Object%5D" rel="hub"/>
  <link href="http://yoursite.com/"/>
  <updated>2018-08-11T03:40:46.715Z</updated>
  <id>http://yoursite.com/</id>
  
  <author>
    <name>朴世超</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>存在关联实体的保存问题</title>
    <link href="http://yoursite.com/2018/08/10/saving-of-associated-entity/"/>
    <id>http://yoursite.com/2018/08/10/saving-of-associated-entity/</id>
    <published>2018-08-10T08:23:23.000Z</published>
    <updated>2018-08-11T03:40:46.715Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题产生"><a href="#问题产生" class="headerlink" title="问题产生"></a>问题产生</h2><p>最开始的时候，是在做非强检器具的编辑功能。添加了一个非强检器具，然后点击编辑，获取对应的对象，然后绑定在表单上，附加参量没有出现。</p><a id="more"></a><p><img src="/image/2018-08-10.1.png" alt=""></p><p>图中红框的位置应该有一个附加参量的编辑部分，但现在没有出现。然后从次开始问题的查找。</p><h2 id="问题定位"><a href="#问题定位" class="headerlink" title="问题定位"></a>问题定位</h2><h3 id="1-检查前台问题"><a href="#1-检查前台问题" class="headerlink" title="1.检查前台问题"></a>1.检查前台问题</h3><p>首先是先检查一下是否是前台出错了，因为这是个动态的表单，所以存在<code>ng-show</code>，检查无误。附加参量的位置使用了<code>ng-repeat</code>，也就是说，只要获取到了数据，附加参量就会显示。</p><h3 id="2-检查jsonview"><a href="#2-检查jsonview" class="headerlink" title="2.检查jsonview"></a>2.检查jsonview</h3><p>调用的是<code>get</code>方法，所以可能是相应的实体上没有添加jsonview，所以在前台没有获取到对应的数据。将所有的关联实体都添加上jsonview后，依然不好使。也不是这个问题。</p><h3 id="3-打印获取的对象"><a href="#3-打印获取的对象" class="headerlink" title="3.打印获取的对象"></a>3.打印获取的对象</h3><p><img src="/image/2018-08-10.2.png" alt=""></p><p>获取的附加参量是一个空数组。到这里可以知道，<code>get</code>方法没有出错。那么既然获取没有问题，那么就只能是保存的时候出现了问题。</p><h3 id="4-查找save的错误"><a href="#4-查找save的错误" class="headerlink" title="4.查找save的错误"></a>4.查找save的错误</h3><p>这个保存的问题还是花了挺长时间才找到的。最后还是因为巧合才发现问题的原因。</p><p>最开始，我的更新方法update在保存的时候使用的是jpa自带的保存方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">update</span><span class="params">(Long id, NonMandatoryInstrument nonMandatoryInstrument)</span> </span>&#123;</div><div class="line">    ...   </div><div class="line">    logger.debug(<span class="string">"持久化更新内容"</span>);</div><div class="line">    nonMandatoryInstrumentRepository.save(oldNonMandatoryInstrument);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这里直接使用<code>repository</code>的save方法，然后我先点击了一下<code>编辑</code>，然后<code>保存</code>。在点击<code>编辑</code>，发现原来的参量也不见了。</p><p><img src="/image/2018-08-10.3.png" alt=""></p><p>然后我将update的保存方法也换成M层的保存方法。就和最上面的问题一样了：<strong>参量能存上，但是附加参量存不上。</strong></p><p>所以我就去看了一下M层的save是怎么写的：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">save</span><span class="params">(NonMandatoryInstrument nonMandatoryInstrument)</span> </span>&#123;</div><div class="line">    logger.debug(<span class="string">"为参数添加非强检器具"</span>);</div><div class="line">    <span class="keyword">for</span>(Parameter parameter: nonMandatoryInstrument.getParameterSet()) &#123;</div><div class="line">        parameter.setNonMandatoryInstrument(nonMandatoryInstrument);</div><div class="line">    &#125;</div><div class="line">    nonMandatoryInstrumentRepository.save(nonMandatoryInstrument);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>发现在保存之前先为每个参量添加了<code>非强检器具</code>这个属性。看到这里我就知道问题所在了：<strong>保存的时候没有设置附加参量的参量属性。</strong></p><h2 id="原因猜测"><a href="#原因猜测" class="headerlink" title="原因猜测"></a>原因猜测</h2><p>首先我们知道<code>非强检器具</code>和<code>参量</code>是<code>一对多</code>的关系。<code>参量</code>和<code>附加参量</code>是<code>一对多</code>的关系。我们在建实体的时候，避免生成中间表，使用了<code>mappedBy</code>这个属性，交由一的一方来维护表。这样就会在<code>参量</code>的表中生成一个<code>非强检器具的外键</code>，所以如果在保存的时候不为参量添加非强检器具，这个外键就是空的。所以在查询的时候就不能关联查询出参量。参量和附加参量也是这个道理。</p><h2 id="问题解决"><a href="#问题解决" class="headerlink" title="问题解决"></a>问题解决</h2><p>解决办法很简单，在保存之前，为附加参量设置参量这个属性。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">save</span><span class="params">(NonMandatoryInstrument nonMandatoryInstrument)</span> </span>&#123;</div><div class="line">    logger.debug(<span class="string">"为参数添加非强检器具"</span>);</div><div class="line">    <span class="keyword">for</span>(Parameter parameter: nonMandatoryInstrument.getParameterSet()) &#123;</div><div class="line">        parameter.setNonMandatoryInstrument(nonMandatoryInstrument);</div><div class="line">        logger.debug(<span class="string">"为附加参量添加参量"</span>);</div><div class="line">        <span class="keyword">for</span> (AdditionalParameter additionalParameter: parameter.getAdditionalParameterSet()) &#123;</div><div class="line">            additionalParameter.setParameter(parameter);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">    nonMandatoryInstrumentRepository.save(nonMandatoryInstrument);</div><div class="line">&#125;</div></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这次的问题解决时间还是比较长的，虽然最终问题是解决了，但是还是暴露出比较多的问题。一个就是对已知的知识掌握的不够灵活，另一个就是debug能力比较弱。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;问题产生&quot;&gt;&lt;a href=&quot;#问题产生&quot; class=&quot;headerlink&quot; title=&quot;问题产生&quot;&gt;&lt;/a&gt;问题产生&lt;/h2&gt;&lt;p&gt;最开始的时候，是在做非强检器具的编辑功能。添加了一个非强检器具，然后点击编辑，获取对应的对象，然后绑定在表单上，附加参量没有出现。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>动态表单集合验证</title>
    <link href="http://yoursite.com/2018/08/06/dynamic-collection-form-validation/"/>
    <id>http://yoursite.com/2018/08/06/dynamic-collection-form-validation/</id>
    <published>2018-08-06T06:39:42.000Z</published>
    <updated>2018-08-11T03:28:43.769Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>我们在做前台的时候，会遇到动态表单的问题，就是只有在我们输入或者点击了某些按钮后才会显示新的页面，而当新显示的页面会有多组的时候，验证就成了我们的问题。</p><a id="more"></a><p><img src="/image/2018-08-08.1.png" alt=""></p><p>例如上图，当我们点击新增参量的时候，会生成下方的参量，而参量1和参量2是相同的表单结构。这时我们要进行表单的验证就会显得有些难度了。</p><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>在解决这个问题之前，我们需要清楚这组动态表单是怎么生成的。</p><h3 id="动态表单的生成"><a href="#动态表单的生成" class="headerlink" title="动态表单的生成"></a>动态表单的生成</h3><p>相同的表单结构，又是动态生成的，所以我们肯定要使用<code>ng-repeat</code>来帮助实现。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"p-m"</span> <span class="attr">ng-repeat</span>=<span class="string">"parameterCategory in data.parameterCategorySet"</span>&gt;</span></div><div class="line">...</div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div></pre></td></tr></table></figure><p>但我们点击<code>新增参量</code>的时候，会新生成一个参量，然后添加进<code>parameterCategorySet</code>中。</p><h3 id="原来验证方法的问题"><a href="#原来验证方法的问题" class="headerlink" title="原来验证方法的问题"></a>原来验证方法的问题</h3><p>上面的代码结构，如果我们还是按照原来的验证方法添加表单校验，就会出现问题。</p><p>按照我们原来的方法，以<code>提示信息</code>的验证为例验证如下：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"p-m"</span> <span class="attr">ng-repeat</span>=<span class="string">"parameterCategory in data.parameterCategorySet"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"row"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-8"</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>提示信息:<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-5"</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">ng-model</span>=<span class="string">"parameterCategory.tips"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> <span class="attr">name</span>=<span class="string">"paramTip"</span> <span class="attr">required</span>=<span class="string">"true"</span> /&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"m-t-xs"</span> <span class="attr">ng-show</span>=<span class="string">"nonMandatoryInstrumentCategoryAddForm.paramTip.$touched &amp;&amp; nonMandatoryInstrumentCategoryAddForm.paramTip.$invalid"</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"text-danger"</span> <span class="attr">ng-show</span>=<span class="string">"nonMandatoryInstrumentCategoryAddForm.paramTip.$error.required"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"fa fa-exclamation-triangle"</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span> 提示信息不能为空 <span class="tag">&lt;/<span class="name">span</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div></pre></td></tr></table></figure><p>我们给<code>input</code>输入框一个<code>name</code>属性,然后在表单的数据不合法并且被点击过的时候显示验证信息。这时会出现下面的问题。</p><p><img src="/image/2018-08-08.2.png" alt=""><br><img src="/image/2018-08-08.3.png" alt=""></p><p>当存在两个参量的时候，我使其中一个出现验证信息，对另一个不做任何操作，但是同样的，另一个也出现了验证信息。类似的，当我们将其中一个的<code>提示信息</code>填写后，两个的验证信息都不出现了。</p><h3 id="问题原因"><a href="#问题原因" class="headerlink" title="问题原因"></a>问题原因</h3><p>出现这个问题的原因是因为本应该不同的两部分表单，使用了相同的<code>name</code>作为标志。就是说我要给小明一个苹果，但是有两个人都叫小明，所以我就给两个小明一人一个苹果了。</p><h3 id="最终解决"><a href="#最终解决" class="headerlink" title="最终解决"></a>最终解决</h3><p>知道原因后，解决的办法就有了。既然不能使用相同的<code>name</code>属性，那我们使用不同的属性不就行了。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"p-m"</span> <span class="attr">ng-repeat</span>=<span class="string">"parameterCategory in data.parameterCategorySet"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"row"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-8"</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>提示信息:<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-5"</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">ng-model</span>=<span class="string">"parameterCategory.tips"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> <span class="attr">name</span>=<span class="string">"&#123;&#123;parameterCategory.name&#125;&#125;ParamTip"</span> <span class="attr">required</span>=<span class="string">"true"</span> /&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"m-t-xs"</span> <span class="attr">ng-show</span>=<span class="string">"nonMandatoryInstrumentCategoryAddForm[parameterCategory.name + 'ParamTip'].$touched &amp;&amp; nonMandatoryInstrumentCategoryAddForm[parameterCategory.name + 'ParamTip'].$invalid"</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"text-danger"</span> <span class="attr">ng-show</span>=<span class="string">"nonMandatoryInstrumentCategoryAddForm[parameterCategory.name + 'ParamTip'].$error.required"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"fa fa-exclamation-triangle"</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span> 提示信息不能为空 <span class="tag">&lt;/<span class="name">span</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div></pre></td></tr></table></figure><p>这里我将input的<code>name</code>属性设置为一个变量，这是根据<code>parameterCategory</code>对象的名字的不同来进行命名的。这样标志就不同了。然后在引用上，使用类似数组的表示方法。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">nonMandatoryInstrumentCategoryAddForm[parameterCategory.name + 'ParamTip']</div></pre></td></tr></table></figure><p>这就对应了<code>提示信息</code>的这个<code>input</code>输入框。</p><p><img src="/image/2018-08-08.4.png" alt=""><br><img src="/image/2018-08-08.5.png" alt=""></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这次的解决办法并没有找很久，主要就是问题定位比较快。</p><p>很多时候，当我们知道了问题所在，并知道是什么原因引起的这个问题，解决问题的办法也就自然而然的出来了。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;我们在做前台的时候，会遇到动态表单的问题，就是只有在我们输入或者点击了某些按钮后才会显示新的页面，而当新显示的页面会有多组的时候，验证就成了我们的问题。&lt;/p&gt;
    
    </summary>
    
    
      <category term="angularjs" scheme="http://yoursite.com/tags/angularjs/"/>
    
  </entry>
  
  <entry>
    <title>Thinkphp 实现多对多</title>
    <link href="http://yoursite.com/2018/06/17/php-manytomany/"/>
    <id>http://yoursite.com/2018/06/17/php-manytomany/</id>
    <published>2018-06-17T02:04:04.000Z</published>
    <updated>2018-06-18T06:12:51.485Z</updated>
    
    <content type="html"><![CDATA[<p>在做实验的时候，要求写一个考试管理系统，这时候就必不可少的要涉及到实体之间的关系,而其中比较难处理的就是多对多关系。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>两个实体，教师和课程，关系多对多。要实现在新建教师的时候能为教师添加多个课程，可编辑，删除时删除相应的关系。</p><a id="more"></a><h2 id="问题解决"><a href="#问题解决" class="headerlink" title="问题解决"></a>问题解决</h2><h3 id="关联定义"><a href="#关联定义" class="headerlink" title="关联定义"></a>关联定义</h3><p>首先，我们肯定要先定义教师和课程的多对多。在教师的模型定义如下：</p><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;</div><div class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">courses</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;belongsToMany(<span class="string">'Course'</span>);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这样就定义了多对多关系，但是还没有结束，还需要去数据库中建立一张中间表<code>teacher_course</code>，然后定义表中字段。到此，关系维护结束。</p><h3 id="关联添加"><a href="#关联添加" class="headerlink" title="关联添加"></a>关联添加</h3><p>因为我们在添加关系的时候，课程和教师都已经存好了，所以这时候我们只用操作中间表。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">$post = Request::instance()-&gt;post();</div><div class="line"></div><div class="line"><span class="comment">// 获取要保存的关联课程</span></div><div class="line">$courseIds = $post[<span class="string">'course_id'</span>];</div><div class="line"></div><div class="line">$Teacher = <span class="keyword">new</span> Teacher();</div><div class="line"></div><div class="line">$Teacher-&gt;name        = $post[<span class="string">'name'</span>];</div><div class="line">$Teacher-&gt;sex         = $post[<span class="string">'sex'</span>];</div><div class="line">$Teacher-&gt;work_number = $post[<span class="string">'work_number'</span>];</div><div class="line">$Teacher-&gt;password    = $post[<span class="string">'password'</span>];</div><div class="line"></div><div class="line"><span class="keyword">if</span> ($Teacher-&gt;save()) &#123;</div><div class="line">    <span class="comment">// 在教师添加成功后修改中间表</span></div><div class="line">    $Teacher-&gt;courses()-&gt;attach($courseIds);</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;success(<span class="string">'保存成功！'</span>, <span class="string">'index'</span>);</div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;error(<span class="string">'保存失败！'</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>获取从V层传过来的数据，包括要保存的所有课程id，然后当教师保存成功后再修改中间表，将教师和课程的id对应的存入中间表中。(<code>attach()</code>这个函数只会操作中间表，另外两个数据表不会被改变。)</p><h3 id="关联删除"><a href="#关联删除" class="headerlink" title="关联删除"></a>关联删除</h3><p>同样的关联删除只能操作中间表。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="keyword">if</span> ($Teacher-&gt;delete()) &#123;</div><div class="line">    <span class="comment">// 获取所有的关联课程，依次删除</span></div><div class="line">    $courses = $Teacher-&gt;courses;</div><div class="line">    <span class="keyword">foreach</span> ($courses <span class="keyword">as</span> $course) &#123;</div><div class="line">        $Teacher-&gt;courses()-&gt;detach($course-&gt;id);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;success(<span class="string">'删除成功！'</span>, url(<span class="string">'index'</span>));</div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;error(<span class="string">'删除失败！'</span>);</div><div class="line">&#125;</div><div class="line">...</div></pre></td></tr></table></figure><p>遍历获取所有的与删除的教师关联的课程，然后遍历删除。(同样，<code>detach()</code>函数也只会操作中间表)</p><h3 id="关联编辑"><a href="#关联编辑" class="headerlink" title="关联编辑"></a>关联编辑</h3><p>编辑稍微复杂一点，需要先将原来的关联关系删除，然后再保存新的关系。也就是将上面的添加和删除合在一起了。这样一分析就简单了。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">$post = Request::instance()-&gt;post();</div><div class="line">$courseIds = $post[<span class="string">'course_id'</span>];</div><div class="line">...</div><div class="line"><span class="keyword">if</span> ($Teacher-&gt;save()) &#123;</div><div class="line">    <span class="comment">// 删除原来的关系</span></div><div class="line">    $courses = $Teacher-&gt;courses;</div><div class="line">    <span class="keyword">foreach</span> ($courses <span class="keyword">as</span> $course) &#123;</div><div class="line">        $Teacher-&gt;courses()-&gt;detach($course-&gt;id);</div><div class="line">    &#125;</div><div class="line">    <span class="comment">// 加入新的关系</span></div><div class="line">    $Teacher-&gt;courses()-&gt;attach($courseIds);</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;success(<span class="string">'保存成功！'</span>, url(<span class="string">'index'</span>));</div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;error(<span class="string">'保存失败！'</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>与添加一样，先获取V层传过来的id数组。然后在教师对象修改完后，去除原来的教师课程关系，然后将新的id存进去。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>最近用惯了java，在维护实体关系的时候都是由<code>hibernate</code>替我们自动维护的，只需要写几个注解和配置项。一方面我们感叹hibernate的强大；但是另一方面，我们有了实现功能的思想，发现自己去实现的时候也并不困难。</p><hr><p><strong>官方参考：</strong><br><a href="https://www.kancloud.cn/manual/thinkphp5/142359" target="_blank" rel="external">https://www.kancloud.cn/manual/thinkphp5/142359</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在做实验的时候，要求写一个考试管理系统，这时候就必不可少的要涉及到实体之间的关系,而其中比较难处理的就是多对多关系。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;两个实体，教师和课程，关系多对多。要实现在新建教师的时候能为教师添加多个课程，可编辑，删除时删除相应的关系。&lt;/p&gt;
    
    </summary>
    
    
      <category term="thinkphp" scheme="http://yoursite.com/tags/thinkphp/"/>
    
  </entry>
  
  <entry>
    <title>Ubuntu16.04 安装nginx</title>
    <link href="http://yoursite.com/2018/06/14/install-nginx/"/>
    <id>http://yoursite.com/2018/06/14/install-nginx/</id>
    <published>2018-06-14T11:49:23.000Z</published>
    <updated>2018-06-15T07:55:05.370Z</updated>
    
    <content type="html"><![CDATA[<p>在ubuntu上安装nginx，安装其实很简单，直接使用<code>Ubuntu</code>自己的软件源就可以安装。但是中间遇到了一些软件源的问题。</p><a id="more"></a><h2 id="安装nginx"><a href="#安装nginx" class="headerlink" title="安装nginx"></a>安装nginx</h2><p>直接使用命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo apt-get install nginx</div></pre></td></tr></table></figure><p>这时候，如果没有出现问题的话，<code>nginx</code>就已经安装完成了。</p><p>但是在我安装的时候出现了如下问题：</p><p><img src="/image/2018-06-14.1.png" alt=""></p><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><p>这个问题出现的原因是<code>post-installation</code>重复安装。</p><p>解决办法：</p><p>1.将文件备份：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo /var/lib/dpkg/info /var/lib/dpkg/info_old</div></pre></td></tr></table></figure><p>2.新建info文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo /var/lib/dpkg/info</div></pre></td></tr></table></figure><p>3.重新生成文件内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">sudo apt-get update</div><div class="line">sudo apt-get -f install</div></pre></td></tr></table></figure><p>4.将<code>info</code>中的文件复制到<code>info_old</code>中</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo mv /var/lib/dpkg/info/* /var/lib/dpkg/info_old</div></pre></td></tr></table></figure><p>5.删除info，将info_old再改回info</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">sudo rm -rf /var/lib/dpkg/info</div><div class="line">sudo mv /var/lib/dpkg/info_old /var/lib/dpkg/info</div></pre></td></tr></table></figure><p>这样之后，再重新安装<code>nginx</code>，安装成功了。</p><h2 id="启动nginx"><a href="#启动nginx" class="headerlink" title="启动nginx"></a>启动nginx</h2><p>成功安装nginx后，启动文件安装在<code>/etc/init.d/</code>下，创建启动脚本<code>nginx</code>。</p><p>启动nginx:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/init.d/nginx start</div></pre></td></tr></table></figure><p><img src="/image/2018-06-14.2.png" alt=""></p><p>安装成功了。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在ubuntu上安装nginx，安装其实很简单，直接使用&lt;code&gt;Ubuntu&lt;/code&gt;自己的软件源就可以安装。但是中间遇到了一些软件源的问题。&lt;/p&gt;
    
    </summary>
    
    
      <category term="nginx" scheme="http://yoursite.com/tags/nginx/"/>
    
      <category term="Ubuntu" scheme="http://yoursite.com/tags/Ubuntu/"/>
    
  </entry>
  
  <entry>
    <title>继承遗留问题</title>
    <link href="http://yoursite.com/2018/06/14/php-construct/"/>
    <id>http://yoursite.com/2018/06/14/php-construct/</id>
    <published>2018-06-14T02:18:40.000Z</published>
    <updated>2018-06-18T02:03:27.161Z</updated>
    
    <content type="html"><![CDATA[<p>这次的软件工程大实验选择使用了<code>thinkphp</code>进行编写。虽然实验写得比较粗糙，但是在实现过程中还是遇到了几个问题的。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>整个系统的界面是采用继承的方式实现的，页面的菜单部分都使用同样的代码。菜单上有一个功能是用户信息。效果是点击它，就可以修改当前登录用户的信息。</p><a id="more"></a><p><img src="/image/2018-06-15.1.png" alt=""></p><h2 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h2><p>应为在登录的时候，通过使用<code>session</code>将当前登录的用户<code>id</code>存了起来。所以直接获取当前登录的id，然后点击按钮的时候将id传入，编辑这个人信息。</p><h2 id="实现过程"><a href="#实现过程" class="headerlink" title="实现过程"></a>实现过程</h2><p>控制器中获取登录用户的id，传入V层：</p><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Session</span>;</div><div class="line">...</div><div class="line">$teacherId = Session::get(<span class="string">'teacherId'</span>);</div><div class="line"><span class="keyword">$this</span>-&gt;assign(<span class="string">'teacherId'</span>, $teacherId);</div><div class="line">...</div></pre></td></tr></table></figure><p>v层直接添加跳转，跳转到编辑的界面：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="tag">&lt;<span class="name">li</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;:url('teacher/edit?id='.$teacherId)&#125;"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"fa fa-user fa-fw"</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span> 用户信息<span class="tag">&lt;/<span class="name">a</span>&gt;</span></div><div class="line">...</div></pre></td></tr></table></figure><p>这时候报了这么一个错：</p><p><img src="/image/2018-06-15.2.png" alt=""></p><p><code>$teacherId</code>没有定义，首先就去检查了一下我有没有拼写出错，发现没有后，检查这个变量是否传过来了，将变量换一个位置，变量存在。这时候陷入了僵局，完全不知道问题所在。又仔细看一一下报错，这时候文件名引起了我的注意，这是一个编译后的文件，将html中的<code>tp</code>代码都进行了转义。</p><p><img src="/image/2018-06-15.3.png" alt=""></p><p>这里突然发现这并不是我以为的文件，报错的位置是另一个文件。看到这里就知道问题的原因了。因为我的菜单使用了继承，所以没有重写的位置，完全使用原来的代码，但是这个时候，这个文件的控制器并没有定义<code>$teacherId</code>这个变量。 </p><p><img src="/image/2018-06-15.4.png" alt=""></p><p>原因找到了，解决起来就简单了。</p><p>控制器使用了继承，有一个基本控制器，在这个基本控制器中定义一个构造函数，通过构造函数获取当前登录的用户id。相当在所有的控制器中都定义了<code>$teacherId</code>了。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>1.通过解决这个问题，又一次发现了快速找到问题原因的重要性。</p><p>2.不要想当然的定位错误。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;这次的软件工程大实验选择使用了&lt;code&gt;thinkphp&lt;/code&gt;进行编写。虽然实验写得比较粗糙，但是在实现过程中还是遇到了几个问题的。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;整个系统的界面是采用继承的方式实现的，页面的菜单部分都使用同样的代码。菜单上有一个功能是用户信息。效果是点击它，就可以修改当前登录用户的信息。&lt;/p&gt;
    
    </summary>
    
    
      <category term="thinkphp" scheme="http://yoursite.com/tags/thinkphp/"/>
    
  </entry>
  
  <entry>
    <title>浅析Patch和Put的区别</title>
    <link href="http://yoursite.com/2018/06/09/patch-and-put/"/>
    <id>http://yoursite.com/2018/06/09/patch-and-put/</id>
    <published>2018-06-09T03:09:54.000Z</published>
    <updated>2018-06-09T04:20:44.877Z</updated>
    
    <content type="html"><![CDATA[<p>在写后台更新接口的时候，定义路由使用<code>@PutMapping</code>，这个注解，但是，后来又改成的<code>@PatchMapping</code>，所以就查了下两者的区别。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>原来在进行更新操作的时候，都是使用<code>put</code>方法来进行请求的，但是这次在写更新的时候，只需要更新一个字段，所以使用了<code>patch</code>方法，那么，<code>patch</code>和<code>put</code>这两者有什么区别呢？</p><a id="more"></a><h2 id="局部与整体"><a href="#局部与整体" class="headerlink" title="局部与整体"></a>局部与整体</h2><p>最基本的，<code>patch</code>是对<code>put</code>的一个补充。举个例子：</p><p>一个计量单位实体<code>MeasurementUnit</code>，他有<code>name</code>，<code>weight</code>，<code>measurementUnitCategory</code>等多个字段，在这里，我们要只修改<code>weight</code>这个字段，这时应该如何选择呢？</p><p>通常，我们为了省事，就会直接将修改了<code>weight</code>的完整的<code>MeasurementUnit</code>对象直接传给后台。但是这种做法实际上并不明智，这会浪费大量的网络带宽。</p><p>但是<code>patch</code>呢，他会只将<code>weight</code>传到制定资源去，表示这是一个局部更新，后端只更新收到的字段。</p><h2 id="幂等性"><a href="#幂等性" class="headerlink" title="幂等性"></a>幂等性</h2><p>另一个方面的区别：<code>put</code>是幂等的，而<code>patch</code>是非幂等的。</p><p>这里有一个比较有意思的概念，叫做<code>幂等性</code>。什么是<code>幂等性</code>呢，就是在请求某一资源的时候，多次操作与一次操作对被操作的对象达到的效果是一样的。简单举个例子：</p><p>用上面的更新来举例子，将权重<code>weight</code>更新为1，这种操作应该是执行多次都是达到同一个效果。</p><p>另一个操作，将<code>weight</code>更新为<code>+1</code>，这种操作显然多次操作就和一次操作不同了。</p><hr><p><strong>友情链接：</strong></p><p><a href="https://segmentfault.com/q/1010000011686226" target="_blank" rel="external">https://segmentfault.com/q/1010000011686226</a></p><p><a href="https://segmentfault.com/q/1010000005685904" target="_blank" rel="external">https://segmentfault.com/q/1010000005685904</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在写后台更新接口的时候，定义路由使用&lt;code&gt;@PutMapping&lt;/code&gt;，这个注解，但是，后来又改成的&lt;code&gt;@PatchMapping&lt;/code&gt;，所以就查了下两者的区别。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;原来在进行更新操作的时候，都是使用&lt;code&gt;put&lt;/code&gt;方法来进行请求的，但是这次在写更新的时候，只需要更新一个字段，所以使用了&lt;code&gt;patch&lt;/code&gt;方法，那么，&lt;code&gt;patch&lt;/code&gt;和&lt;code&gt;put&lt;/code&gt;这两者有什么区别呢？&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
      <category term="http" scheme="http://yoursite.com/tags/http/"/>
    
  </entry>
  
  <entry>
    <title>PostMapping处理参数”/“</title>
    <link href="http://yoursite.com/2018/06/08/postmapping-param/"/>
    <id>http://yoursite.com/2018/06/08/postmapping-param/</id>
    <published>2018-06-08T04:17:02.000Z</published>
    <updated>2018-06-09T03:58:10.111Z</updated>
    
    <content type="html"><![CDATA[<p><code>PostMapping</code>这是Spring中的定义路由的注解，以前没有关注过这个注解的默认值，所以在实现的时候就显得不那么灵活。</p><a id="more"></a><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>有一个路由是这么定义的：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@PostMapping</span>(<span class="string">"/"</span>)</div></pre></td></tr></table></figure><p>没有实际的路由，只有一个”/“，这时候，我们可以使用@PostMapping的默认值来代替上面的写法：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@PostMapping</span></div></pre></td></tr></table></figure><p>然后我们在访问的时候，什么也不用做修改，和上面那种写法的访问路由完全相同。</p><h2 id="默认值"><a href="#默认值" class="headerlink" title="默认值"></a>默认值</h2><p>发现这个现象的时候，首先就去看了一下这个注解的默认值。</p><p><img src="/image/2018-06-08.1.png" alt=""></p><p>默认值是<code>&quot;&quot;</code>,所以什么都不写就相当于<code>@PostMapping(&quot;&quot;)</code>.这时我们访问这个方法的时候路由应该这么写：<code>/XXX</code>。</p><h2 id="多余的”-“"><a href="#多余的”-“" class="headerlink" title="多余的”/“"></a>多余的”/“</h2><p>在将路由修改后，本应该将单元测试的访问路由一起修改的，但是我在第一遍进行单元测试的时候，并没有修改原来的路由：<code>/XXX/</code>。而单元测试依然通过。</p><p>所以在处理最后一个<code>”/“</code>的时候，在没有匹配的情况下，他会自动的将斜杠去掉。这就好像我们在浏览器中输入<code>www.baidu.com/</code>，这时候我们依然能访问的是<code>www.baidu.com</code>。Spring为我们将多余的斜杠去除了。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;code&gt;PostMapping&lt;/code&gt;这是Spring中的定义路由的注解，以前没有关注过这个注解的默认值，所以在实现的时候就显得不那么灵活。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>Spring AOP 学习简记</title>
    <link href="http://yoursite.com/2018/06/04/spring-aop-study/"/>
    <id>http://yoursite.com/2018/06/04/spring-aop-study/</id>
    <published>2018-06-04T02:55:53.000Z</published>
    <updated>2018-06-09T04:17:43.122Z</updated>
    
    <content type="html"><![CDATA[<p>最近在学习Spring上的AOP，通过官方文档和慕课网上的一个课程，对AOP有了一些了解。在这里做下记录。</p><h2 id="什么是AOP"><a href="#什么是AOP" class="headerlink" title="什么是AOP"></a>什么是AOP</h2><p>相信大家对于<code>AOP</code>这个词都不陌生：面向切面编程。在解释这个概念的时候就不得不说一下他的适用情况了。在实际项目中，有一部分是主要的业务逻辑，而还有一部分很重要的就是<code>非功能性需求</code>，比如权限判断，事务控制，异常处理等等。这些功能有个共同的特点就是他们会贯穿项目，我们可能在很多的地方都需要做一些为了系统安全的操作，而这些操作又不能将他们放到业务逻辑中去，那样就会使我们的业务逻辑实现变得复杂。这时候就需要AOP这一利器。它会在某一个层面上统一执行一些操作，而这些操作我们在实现业务逻辑的时候就完全不用去考虑了。</p><p>简言之，AOP就是从复杂的业务逻辑中将非功能性需求抽离出来的办法。</p><a id="more"></a><h2 id="Spring是如何实现AOP的"><a href="#Spring是如何实现AOP的" class="headerlink" title="Spring是如何实现AOP的"></a>Spring是如何实现AOP的</h2><p>Spring在为我们实现AOP的时候提供了很好的支持。<a href="https://docs.spring.io/spring/docs/4.3.18.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#aop" target="_blank" rel="external">https://docs.spring.io/spring/docs/4.3.18.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#aop</a></p><h3 id="Aspect类"><a href="#Aspect类" class="headerlink" title="Aspect类"></a>Aspect类</h3><p>首先我们需要建立一个Aspect类，用来定义切面和执行切面的操作。在这个切面类中，首选需要定义一个切点：<code>@Pointcut</code>，它会告诉我们在哪里执行<code>切</code>的操作。然后就是定义advice函数，这些函数主要是告诉我们在<code>切</code>的时候执行什么操作。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Aspect</span> <span class="comment">// 声明这个是一个切面</span></div><div class="line"><span class="meta">@Component</span>  <span class="comment">// 声明这个是一个组件。由于切面中，并没有包含Component，所以如果想让spring扫描到，必须那入@Component注解</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InstrumentOwnerCheckAspect</span> </span>&#123;</div><div class="line">...</div><div class="line">    <span class="meta">@Pointcut</span>(<span class="string">"@annotation(com.mengyunzhi.measurement.annotation.InstrumentOwnerCheckAnnotation) &amp;&amp; args(id,..)"</span>)</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doAccessCheck</span><span class="params">(Long id)</span> </span>&#123;&#125;</div><div class="line"></div><div class="line">    <span class="meta">@Before</span>(<span class="string">"doAccessCheck(id)"</span>)</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">before</span><span class="params">(Long id)</span> <span class="keyword">throws</span> ObjectNotFoundException, AccessDeniedException </span>&#123;</div><div class="line">        ...</div><div class="line">    &#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure><blockquote><p>值得注意的是，在定义Aspect这个类的时候，我们需要使用<code>@Component</code>这个注解，以使它在项目启动的时候能够被Spring扫描到。</p></blockquote><h3 id="匹配注解"><a href="#匹配注解" class="headerlink" title="匹配注解"></a>匹配注解</h3><p>这个概念是对如何实现切的操作而说的。</p><p><img src="/image/2018-06-08.1.jpg" alt=""></p><p>这是说通过某一个注解就可以实现切的操作。</p><p>在这几个中，比较常用的是<code>@annotation</code>：在方法上使用注解。参数是告诉我们使用哪个注解，比如上面使用的就是<code>AdminOnly</code>注解。</p><blockquote><p>有一个比较特殊的，是匹配方法：<code>execution</code>，它只能在某个方法的地方切。</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 在所有的public方法上切</span></div><div class="line"><span class="meta">@Pointcut</span>(<span class="string">"execution(public * *(..))"</span>)</div></pre></td></tr></table></figure><blockquote><p>他的用法在<a href="https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/aop.html#aop-pointcuts-examples" target="_blank" rel="external">https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/aop.html#aop-pointcuts-examples</a>上还要很多，这里就不一一介绍了。</p></blockquote><h3 id="匹配参数"><a href="#匹配参数" class="headerlink" title="匹配参数"></a>匹配参数</h3><p>匹配参数是同样也是在告诉我们在什么地方执行<code>切</code>的操作，不同的是，它只能告诉我们切点的参数是什么样子。所以匹配参数都是在切方法的时候用的。</p><p>参数匹配主要有两种<code>execution</code>和<code>args</code>：</p><p><img src="/image/2018-06-08.2.jpg" alt=""></p><blockquote><p>这里推荐使用<code>args</code>。</p></blockquote><h3 id="五大Advice"><a href="#五大Advice" class="headerlink" title="五大Advice"></a>五大Advice</h3><p>advice是告诉我们在执行切的时候应该做什么的，而五大advice是根据在切点不同位置执行操作而区分的。</p><p><img src="/image/2018-06-08.3.jpg" alt=""></p><h2 id="示例代码解读"><a href="#示例代码解读" class="headerlink" title="示例代码解读"></a>示例代码解读</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="meta">@Pointcut</span>(<span class="string">"@annotation(com.mengyunzhi.measurement.annotation.InstrumentOwnerCheckAnnotation) &amp;&amp; args(id,..)"</span>)</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doAccessCheck</span><span class="params">(Long id)</span> </span>&#123;&#125;</div><div class="line"></div><div class="line"><span class="meta">@Before</span>(<span class="string">"doAccessCheck(id)"</span>)</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">before</span><span class="params">(Long id)</span> <span class="keyword">throws</span> ObjectNotFoundException, AccessDeniedException </span>&#123;</div><div class="line">    ...</div><div class="line">&#125;</div><div class="line">...</div></pre></td></tr></table></figure><p>切点：<code>InstrumentOwnerCheckAnnotation</code>注解。参数：第一个参数是<code>id</code>的方法。</p><p><code>@Before</code>在切之前执行操作。</p><p>所以上面的意思就是，在所有使用<code>@InstrumentOwnerCheckAnnotation</code>注解，并且第一个参数是<code>id</code>的方法处切，然后在切之前执行<code>before</code>方法。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Spring的AOP帮助我们能够更加专注于实现某一部分的业务逻辑，而忽视夹杂其间的非功能性需求，在最大的可能上降低了我们的项目的整体耦合性，从而更好的实现面向对象的思想。</p><hr><p><strong>友情链接：</strong></p><p><a href="https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/aop.html" target="_blank" rel="external">https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/aop.html</a></p><p><a href="https://www.imooc.com/learn/869" target="_blank" rel="external">https://www.imooc.com/learn/869</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近在学习Spring上的AOP，通过官方文档和慕课网上的一个课程，对AOP有了一些了解。在这里做下记录。&lt;/p&gt;
&lt;h2 id=&quot;什么是AOP&quot;&gt;&lt;a href=&quot;#什么是AOP&quot; class=&quot;headerlink&quot; title=&quot;什么是AOP&quot;&gt;&lt;/a&gt;什么是AOP&lt;/h2&gt;&lt;p&gt;相信大家对于&lt;code&gt;AOP&lt;/code&gt;这个词都不陌生：面向切面编程。在解释这个概念的时候就不得不说一下他的适用情况了。在实际项目中，有一部分是主要的业务逻辑，而还有一部分很重要的就是&lt;code&gt;非功能性需求&lt;/code&gt;，比如权限判断，事务控制，异常处理等等。这些功能有个共同的特点就是他们会贯穿项目，我们可能在很多的地方都需要做一些为了系统安全的操作，而这些操作又不能将他们放到业务逻辑中去，那样就会使我们的业务逻辑实现变得复杂。这时候就需要AOP这一利器。它会在某一个层面上统一执行一些操作，而这些操作我们在实现业务逻辑的时候就完全不用去考虑了。&lt;/p&gt;
&lt;p&gt;简言之，AOP就是从复杂的业务逻辑中将非功能性需求抽离出来的办法。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
      <category term="Spring" scheme="http://yoursite.com/tags/Spring/"/>
    
  </entry>
  
  <entry>
    <title>在控制器中使用过滤器</title>
    <link href="http://yoursite.com/2018/06/01/use-filter-in-controller/"/>
    <id>http://yoursite.com/2018/06/01/use-filter-in-controller/</id>
    <published>2018-06-01T12:11:07.000Z</published>
    <updated>2018-06-02T07:03:15.954Z</updated>
    
    <content type="html"><![CDATA[<p>在以前的项目中，只有在V层使用过过滤器，前面我也介绍过滤过滤器的使用，但是在<code>angular</code>这么强大的框架，是不可能让我们失望的。在C层<code>controller</code>中同样可以使用过滤器。</p><a id="more"></a><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>查询的实现使用了过滤器，然后还要实现分页。这个过滤器如果还是像以前一样在V层使用过滤器，那么就会先实现分页，然后再去查询的时候，分页的数据不会改变。比如查询出10条数据，那么分页获取的数据总数就是10条，然后过滤掉3条，这时页面上就会显示7条数据，但是分页获取的数据总数还是10条，这样就出现了数据的不同步。</p><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><h3 id="1-如何在controller使用过滤器"><a href="#1-如何在controller使用过滤器" class="headerlink" title="1.如何在controller使用过滤器?"></a>1.如何在<code>controller</code>使用过滤器?</h3><p>首先先介绍一下过滤器在controller中的使用。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">angular.module(<span class="string">'myApp'</span>)</div><div class="line">.controller(<span class="string">'myController'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">$filter</span>) </span>&#123;</div><div class="line">...</div><div class="line">&#125;);</div></pre></td></tr></table></figure><p>首先在开始的时候将<code>$filter</code>注入进来</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">angular.module(<span class="string">'myApp'</span>)</div><div class="line">.controller(<span class="string">'myController'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">$filter</span>) </span>&#123;</div><div class="line">$filter(<span class="string">'myFilter'</span>)(param1, param2...);</div><div class="line">&#125;);</div></pre></td></tr></table></figure><p>然后使用$filter来注入你自己定义的过滤器，第一个括号中是个自己的过滤器的名子，后面的过滤器的参数。值得注意的是，<strong>这里我们要将过滤的对象放在第一个参数的位置。</strong></p><h3 id="2-解决问题"><a href="#2-解决问题" class="headerlink" title="2.解决问题"></a>2.解决问题</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">tbody</span> <span class="attr">ng-repeat</span>=<span class="string">"person in persons | yunzhiPersonnel: filterParams.qualifierCertificateType: filterParams.validityDate | yunzhiQualifierNumber: filterParams.number"</span>&gt;</span></div></pre></td></tr></table></figure><p>原来的过滤器我是这么使用的。现在将过滤器放到controller中。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="comment">// 提交查询</span></div><div class="line">self.submit = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    $scope.filterParams = self.getFilterParams(); <span class="comment">// 设置过滤条件</span></div><div class="line">    PersonnelPersonnelsupervisefileService.getAllBySpecification(self.getQueryParams(), <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</div><div class="line">        $scope.persons = data; <span class="comment">// 传入v层</span></div><div class="line"></div><div class="line">        <span class="comment">// 在这里调用过滤器，原因是为了适应分页的使用，需要在分页之前执行完查询，否则会出现少数据的现象。</span></div><div class="line">        $scope.persons = $filter(<span class="string">'yunzhiPersonnel'</span>)($scope.persons, $scope.filterParams.qualifierCertificateType, $scope.filterParams.validityDate);</div><div class="line">        $scope.persons = $filter(<span class="string">'yunzhiQualifierNumber'</span>)($scope.persons, $scope.filterParams.number);</div><div class="line"></div><div class="line">        self.reload(); <span class="comment">// 重新加载，显示分页</span></div><div class="line">    &#125;);</div><div class="line">&#125;;</div><div class="line">...</div></pre></td></tr></table></figure><p>这样在每次查询的时候，都先将查询的结果过滤一下，然后再对过滤的结果进行分页，就不会在出现数据对不上的现象了。</p><blockquote><p>官方参考：<a href="https://docs.angularjs.org/api/ng/filter/filter" target="_blank" rel="external">https://docs.angularjs.org/api/ng/filter/filter</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在以前的项目中，只有在V层使用过过滤器，前面我也介绍过滤过滤器的使用，但是在&lt;code&gt;angular&lt;/code&gt;这么强大的框架，是不可能让我们失望的。在C层&lt;code&gt;controller&lt;/code&gt;中同样可以使用过滤器。&lt;/p&gt;
    
    </summary>
    
    
      <category term="angularjs" scheme="http://yoursite.com/tags/angularjs/"/>
    
  </entry>
  
  <entry>
    <title>实现 n:1 的查询</title>
    <link href="http://yoursite.com/2018/05/30/filter/"/>
    <id>http://yoursite.com/2018/05/30/filter/</id>
    <published>2018-05-30T07:52:19.000Z</published>
    <updated>2018-06-02T06:53:41.458Z</updated>
    
    <content type="html"><![CDATA[<p>最近实现了一个查询，在查询中遇到了一些问题，在这里记录一下。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>在实现一个人员的查询功能的时候，有两个查询条件：<code>人员资质</code>和<code>有效期至</code>，人员和人员资质的关系是<code>1：n</code>，有效期至是人员资质的一个字段。在实现这个查寻的时候，而在后台通过n的一方来查询1的一方是很不好实现的。</p><a id="more"></a><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><p>这个问题最后考虑在前台使用过滤器来实现，首先将满足其他查询条件的查询出来，然后将没有相应人员资质的人员过滤掉，这样就实现了。</p><h2 id="解决过程"><a href="#解决过程" class="headerlink" title="解决过程"></a>解决过程</h2><h3 id="1-引入过滤器"><a href="#1-引入过滤器" class="headerlink" title="1.引入过滤器"></a>1.引入过滤器</h3><p>首先我们知道，过滤器是通过管道符来使用的：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">objects | filter</div></pre></td></tr></table></figure><p>然后就是过滤器参数的问题，在管道符前面的<code>objects</code>就是第一个参数，过滤器至少有一个参数。现在有人员资质和有效期至，这两个是过滤的条件，必然也要作为参数。那么过滤器是如何传参的呢？</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">objects | filter: param</div></pre></td></tr></table></figure><p>在过滤器后面写一个冒号<code>:</code>，然后冒号后面的就是参数。那两个参数呢？</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">objects | filter: param1: param2</div></pre></td></tr></table></figure><p>连续使用冒号<code>:</code>就可以传多个参数了。好了，下面来解决我们的问题。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">tbody</span> <span class="attr">ng-repeat</span>=<span class="string">"person in persons | yunzhiPersonnel: params.qualifierCertificateType: params.validityDate"</span>&gt;</span></div></pre></td></tr></table></figure><p>然后实现过滤器的基本思想就是首先遍历人员，再遍历人员中的人员资质，当人员资质和查询的人员资质相同的时候，就将这个人员放到返回列表中，最后统一返回。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line">self.getQualifierWithQualifierCertificate = <span class="function"><span class="keyword">function</span>(<span class="params">personnels, qualifierCertificateType, validityDate</span>) </span>&#123;</div><div class="line">    <span class="keyword">var</span> persons = []; <span class="comment">// 初始化符合条件的人员</span></div><div class="line"></div><div class="line">    <span class="comment">// 遍历人员</span></div><div class="line">    angular.forEach(personnels, <span class="function"><span class="keyword">function</span>(<span class="params">personnel</span>) </span>&#123;</div><div class="line">        <span class="keyword">var</span> qualifierCertificates = personnel.qualifier.qualifierCertificate; <span class="comment">// 获取人员资质</span></div><div class="line"></div><div class="line">        <span class="comment">// 如果输入了两个查询条件</span></div><div class="line">        <span class="keyword">if</span> (qualifierCertificateType.id &amp;&amp; validityDate) &#123;</div><div class="line"></div><div class="line">            <span class="comment">// 遍历人员资质</span></div><div class="line">            angular.forEach(qualifierCertificates, <span class="function"><span class="keyword">function</span>(<span class="params">qualifierCertificates</span>) </span>&#123;</div><div class="line"></div><div class="line">                <span class="comment">// 当资格证类别与查询的资格证类别相同，并且有效期至也相同时，将人员放入返回人员数组中</span></div><div class="line">                <span class="keyword">if</span> (qualifierCertificates.qualifierCertificateType.name === qualifierCertificateType.name &amp;&amp; qualifierCertificates.validityDate === validityDate) &#123;</div><div class="line">                    persons.push(personnel);</div><div class="line">                &#125;</div><div class="line">            &#125;);</div><div class="line">            <span class="comment">// 如果输入资格证类别    </span></div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (qualifierCertificateType.id) &#123;</div><div class="line">            <span class="comment">// 遍历人员资质</span></div><div class="line">            angular.forEach(qualifierCertificates, <span class="function"><span class="keyword">function</span>(<span class="params">qualifierCertificates</span>) </span>&#123;</div><div class="line">                <span class="comment">// 资格证类别与查询的资格证类别相同</span></div><div class="line">                <span class="keyword">if</span> (qualifierCertificates.qualifierCertificateType.name === qualifierCertificateType.name) &#123;</div><div class="line">                    persons.push(personnel);</div><div class="line">                &#125;</div><div class="line">            &#125;);</div><div class="line">            <span class="comment">// 输入有效期至   </span></div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            <span class="comment">// 遍历人员资质</span></div><div class="line">            angular.forEach(qualifierCertificates, <span class="function"><span class="keyword">function</span>(<span class="params">qualifierCertificates</span>) </span>&#123;</div><div class="line">                <span class="comment">// 有效期至与查询的有效期至相同</span></div><div class="line">                <span class="keyword">if</span> (qualifierCertificates.validityDate === validityDate) &#123;</div><div class="line">                    persons.push(personnel);</div><div class="line">                &#125;</div><div class="line">            &#125;);</div><div class="line">        &#125;</div><div class="line">    &#125;);</div><div class="line"></div><div class="line">    <span class="keyword">return</span> persons;</div><div class="line"></div><div class="line">&#125;;</div><div class="line">...</div></pre></td></tr></table></figure><h3 id="2-过滤器及时生效"><a href="#2-过滤器及时生效" class="headerlink" title="2.过滤器及时生效"></a>2.过滤器及时生效</h3><p>上面我在设置参数的时候，直接将查询的参数当做过滤参数，所以一旦输入了查询条件，就会直接过滤。而我们要的效果是，在用户点击查询后在显示过滤后的数据。</p><p>首先想到的是，在给这个过滤器一个参数：是否点击了查询。只有当用户点击了查询，这个参数为<code>true</code>，然后执行过滤，没有点击，这个参数为<code>false</code>，不执行过滤。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">tbody</span> <span class="attr">ng-repeat</span>=<span class="string">"person in persons | yunzhiPersonnel: params.qualifierCertificateType: params.validityDate：touched"</span>&gt;</span></div></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="keyword">if</span>(touched) &#123;</div><div class="line"><span class="keyword">return</span> self.getQualifierWithQualifierCertificate(personnels, qualifierCertificateType, validityDate);</div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line"><span class="keyword">return</span> personnels;</div><div class="line">&#125;</div><div class="line">...</div></pre></td></tr></table></figure><p>但是这种解决方法并不好。一个问题是，这种解决方法会带来一些其他的问题，比如说先查询了一次，再查询一次就又会出现上面直接出结果的问题；另一个问题，也是主要的问题，这种方法不符合规范，过滤器的职能就是过滤，不应该在过滤器中判断什么时候开始过滤，什么时候不过滤，而应该是我在需要过滤的时候，再给他过滤条件，不需要过滤的时候，就不给他过滤条件。</p><p>所以，在控制器中重新定义一个函数，用来获取过滤条件，这个方法在点击查询的时候调用。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">tbody</span> <span class="attr">ng-repeat</span>=<span class="string">"person in persons | yunzhiPersonnel: filterParams.qualifierCertificateType: filterParams.validityDate"</span>&gt;</span></div></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 获取过滤参数</span></div><div class="line">self.getFilterParams = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> &#123;</div><div class="line">        qualifierCertificateType: $scope.params.qualifierCertificateType, <span class="comment">// 资格证类别</span></div><div class="line">        validityDate: $scope.params.validityDate, <span class="comment">// 有效期至</span></div><div class="line">        <span class="comment">// 这里还可以添加其他过滤条件</span></div><div class="line">    &#125;;</div><div class="line">&#125;;</div><div class="line"></div><div class="line"><span class="comment">// 提交查询</span></div><div class="line">self.submit = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    ...</div><div class="line">    $scope.filterParams = self.getFilterParams(); <span class="comment">// 设置过滤条件</span></div><div class="line">    ...</div><div class="line">&#125;;</div></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>我们这种mvc的开发思想，在实现每一部分的时候，都要尽可能的使每一部分都只做自己的功能，这样不仅能增加代码的可读性，同时也增加了可维护性，在后面进行改写的时候也会减小压力。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近实现了一个查询，在查询中遇到了一些问题，在这里记录一下。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;在实现一个人员的查询功能的时候，有两个查询条件：&lt;code&gt;人员资质&lt;/code&gt;和&lt;code&gt;有效期至&lt;/code&gt;，人员和人员资质的关系是&lt;code&gt;1：n&lt;/code&gt;，有效期至是人员资质的一个字段。在实现这个查寻的时候，而在后台通过n的一方来查询1的一方是很不好实现的。&lt;/p&gt;
    
    </summary>
    
    
      <category term="angularjs" scheme="http://yoursite.com/tags/angularjs/"/>
    
  </entry>
  
  <entry>
    <title>关于实现下拉选框的默认选中问题</title>
    <link href="http://yoursite.com/2018/05/27/selected-by-default/"/>
    <id>http://yoursite.com/2018/05/27/selected-by-default/</id>
    <published>2018-05-27T06:45:09.000Z</published>
    <updated>2018-05-27T08:35:03.544Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>在<code>angular</code>项目中，点击编辑人员操作，会在表单中默认显示选择的人员的信息，信息以下拉选框的形式展现，每个下拉选框都是一个指令。这时，<code>技术机构</code>指令和<code>管理部门</code>指令均以同一个字段：<code>department</code>作为他们的选项。他们两个都是部门，只是类型不同。对于同一个人员，只能有一个部门，所以要默认显示技术机构或管理部门。</p><a id="more"></a><h2 id="排查原因"><a href="#排查原因" class="headerlink" title="排查原因"></a>排查原因</h2><p>首先看一下我们的两个指令：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showInstrumentUser"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>技术机构<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-instrument-user</span> <span class="attr">ng-model</span>=<span class="string">"data.department"</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">data-config</span>=<span class="string">"&#123;departmentType: '技术机构'&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-instrument-user</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showManagementDepartment"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>管理部门<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-management-department</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">ng-model</span>=<span class="string">"data.department"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-management-department</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">...</div></pre></td></tr></table></figure><p><img src="/image/2018-05-27.1.png" alt=""></p><p>上面是我点击编辑后，根据id获取的人员有一个部门字段，内容为管理部门，这时应该默认选中管理部门。但是并没有选择上。所以让我们删除一下技术机构再看一下效果。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showManagementDepartment"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>管理部门<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-management-department</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">ng-model</span>=<span class="string">"data.department"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-management-department</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">...</div></pre></td></tr></table></figure><p><img src="/image/2018-05-27.2.png" alt=""></p><p>这回默认选中了管理部门。这里不妨大胆的猜测一下原因：</p><blockquote><p><strong>由于技术机构的存在，我们将部门传进指令中，没有对应的技术机构，所以部门就成了空。</strong></p></blockquote><p>让我们将技术机构再放回来，然后调换一下两个指令的位置。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showManagementDepartment"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>管理部门<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-management-department</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">ng-model</span>=<span class="string">"data.department"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-management-department</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showInstrumentUser"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>技术机构<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-instrument-user</span> <span class="attr">ng-model</span>=<span class="string">"data.department"</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">data-config</span>=<span class="string">"&#123;departmentType: '技术机构'&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-instrument-user</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">...</div></pre></td></tr></table></figure><p><img src="/image/2018-05-27.3.png" alt=""></p><p>可以看到管理部门同样被默认选择上了，说明我们上面的猜测正确。</p><p>由于<code>ng-model</code>在angularjs中会使数据双向绑定，当前面的技术机构没有对应的对象存在时，它就会选中空值，这时又将这个空值绑定在ng-model上。两个指令的ng-model都绑定的是统一数据，所以后面的管理部门在取选中的时候，就是根据空值来选择的，当然选择不上了。</p><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><p>我们最开始在controller中通过id获取对象时，直接将返回的对象中的属性给<code>ng-model</code>了，导致两个指令对应同一参数。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line">self.getOneById = <span class="function"><span class="keyword">function</span>(<span class="params">id</span>) </span>&#123;</div><div class="line">    PersonnelPersonnelsupervisefileService.getOneById(id, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</div><div class="line">        $scope.data = data;</div><div class="line">    &#125;;</div><div class="line">&#125;;</div><div class="line">...</div></pre></td></tr></table></figure><p>既然两个指令绑定同一变量会混乱，那我让他们绑定不同的变量是不是就可以了呢？</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line">$scope.instrumentUser = <span class="literal">undefined</span>;<span class="comment">// 初始化技术机构</span></div><div class="line">$scope.managementDepartment = <span class="literal">undefined</span>;<span class="comment">// 初始化管理部门</span></div><div class="line">self.getOneById = <span class="function"><span class="keyword">function</span>(<span class="params">id</span>) </span>&#123;</div><div class="line">    PersonnelPersonnelsupervisefileService.getOneById(id, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</div><div class="line">        $scope.data = data; <span class="comment">// 赋值</span></div><div class="line">        $scope.params.district = data.department.district; <span class="comment">// 为区域赋值</span></div><div class="line"></div><div class="line">        <span class="comment">// 如果数据的部门是管理部门,为管理部门赋值</span></div><div class="line">        <span class="keyword">if</span> (data.department.departmentType.pinyin === <span class="string">"guanlibumen"</span>) &#123;</div><div class="line">            $scope.managementDepartment = data.department;</div><div class="line"></div><div class="line">            <span class="comment">// 如果数据的部门是技术机构，为技术机构赋值</span></div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (data.department.departmentType.pinyin === <span class="string">"jishujigou"</span>) &#123;</div><div class="line">            $scope.instrumentUser = data.department;</div><div class="line">        &#125;</div><div class="line">    &#125;);</div><div class="line">&#125;;</div><div class="line">...</div></pre></td></tr></table></figure><p>首先定义两个变量，用来绑定不同的指令，当我们编辑的人员的部门的类型是技术机构，就为<code>技术机构</code>这个对象赋值；如果为部门类型是管理部门，就为<code>管理部门</code>赋值；否则均不赋值。然后再让两个指令绑定不同的变量。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showInstrumentUser"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>技术机构<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-instrument-user</span> <span class="attr">ng-model</span>=<span class="string">"instrumentUser"</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">data-config</span>=<span class="string">"&#123;departmentType: '技术机构'&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-instrument-user</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span> <span class="attr">ng-show</span>=<span class="string">"showManagementDepartment"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>管理部门<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">yunzhi-management-department</span> <span class="attr">data-district</span>=<span class="string">"params.district"</span> <span class="attr">ng-model</span>=<span class="string">"managementDepartment"</span>&gt;</span><span class="tag">&lt;/<span class="name">yunzhi-management-department</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div></pre></td></tr></table></figure><p>到此，问题解决。但是肯定有细心的小朋友发现了，你在这里将部门用两个变量来表示，但对于人员来说这两个都不是我们要的字段，那保存的时候怎么绑定部门呢？</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">$scope.$watch(<span class="string">'[instrumentUser, managementDepartment]'</span>, </div><div class="line"><span class="function"><span class="keyword">function</span>(<span class="params">newValue</span>) </span>&#123;</div><div class="line">    <span class="keyword">var</span> instrumentUser = newValue[<span class="number">0</span>]; <span class="comment">// 技术机构</span></div><div class="line">    <span class="keyword">var</span> managementDepartment = newValue[<span class="number">1</span>]; <span class="comment">// 管理部门</span></div><div class="line"></div><div class="line">    <span class="comment">// 当选择了技术机构，为监督抽查人员的部门字段赋值</span></div><div class="line">    <span class="keyword">if</span> (instrumentUser &amp;&amp; instrumentUser.id) &#123;</div><div class="line">        $scope.data.department = instrumentUser;</div><div class="line"></div><div class="line">        <span class="comment">// 当选择了管理部门，为监督抽查人员的部门字段赋值</span></div><div class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (managementDepartment &amp;&amp; managementDepartment.id) &#123;</div><div class="line">        $scope.data.department = managementDepartment;</div><div class="line"></div><div class="line">        <span class="comment">// 当什么都没选时，为监督抽查人员的部门字段赋空值</span></div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        <span class="keyword">if</span> ($scope.data) &#123;</div><div class="line">            $scope.data.department = instrumentUser = managementDepartment;</div><div class="line">        &#125;</div><div class="line">    &#125;, <span class="literal">true</span>);</div></pre></td></tr></table></figure><p>在这里我们监听一下技术机构和管理部门，当他们选择的时候，将他们选择的值赋给人员的部门。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这次的问题中，显然我们的解决办法显得并不是多么高深的方法，很简单。所以解决问题的关键在快速的定位问题产生的原因，当原因找到后，问题也就迎刃而解了。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;在&lt;code&gt;angular&lt;/code&gt;项目中，点击编辑人员操作，会在表单中默认显示选择的人员的信息，信息以下拉选框的形式展现，每个下拉选框都是一个指令。这时，&lt;code&gt;技术机构&lt;/code&gt;指令和&lt;code&gt;管理部门&lt;/code&gt;指令均以同一个字段：&lt;code&gt;department&lt;/code&gt;作为他们的选项。他们两个都是部门，只是类型不同。对于同一个人员，只能有一个部门，所以要默认显示技术机构或管理部门。&lt;/p&gt;
    
    </summary>
    
    
      <category term="angularjs" scheme="http://yoursite.com/tags/angularjs/"/>
    
  </entry>
  
  <entry>
    <title>Angularjs中的$watch（二）</title>
    <link href="http://yoursite.com/2018/05/21/angular-watch-2/"/>
    <id>http://yoursite.com/2018/05/21/angular-watch-2/</id>
    <published>2018-05-21T08:20:25.000Z</published>
    <updated>2018-05-21T11:44:47.771Z</updated>
    
    <content type="html"><![CDATA[<p>上次介绍了两种<code>$watch</code>的用法，今天在跟大家分享另外的几种用法。</p><a id="more"></a><h2 id="watch监听函数"><a href="#watch监听函数" class="headerlink" title="$watch监听函数"></a>$watch监听函数</h2><p>将监听的参数部分换为函数。虽然监听的是函数，但实际上监听的是函数的返回值。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">$scope.food = <span class="number">1</span>;</div><div class="line">$scope.foodCounter = <span class="number">0</span>;</div><div class="line">$scope.$watch(</div><div class="line">    <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="keyword">return</span> $scope.food; &#125;,</div><div class="line">    <span class="function"><span class="keyword">function</span>(<span class="params">newValue, oldValue</span>) </span>&#123;</div><div class="line">        <span class="keyword">if</span> (newValue !== oldValue) &#123;</div><div class="line">        <span class="built_in">console</span>.log(newValue);</div><div class="line">            $scope.foodCounter = $scope.foodCounter + <span class="number">1</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">);</div></pre></td></tr></table></figure><p><img src="/image/2018-05-21.1.png" alt=""><br><img src="/image/2018-05-21.2.png" alt=""></p><p>然后让我们看一下我们监听的部分，看看是不是我们的返回值：</p><p><img src="/image/2018-05-21.3.png" alt=""></p><h2 id="watchGroup-watchExpressions-listener"><a href="#watchGroup-watchExpressions-listener" class="headerlink" title="$watchGroup(watchExpressions, listener)"></a>$watchGroup(watchExpressions, listener)</h2><p><code>$watchGroup</code>是scope上的另一个函数，他是<code>$watch</code>的功能扩展。他可以监听一个数组中的多个元素，当其中的人一个发生改变时，都会被监听到。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$scope.v1 = <span class="string">'a'</span>;</div><div class="line">$scope.v2 = <span class="string">'a'</span>;</div><div class="line">$scope.$watchGroup([<span class="string">'v1'</span>, <span class="string">'v2'</span>], <span class="function"><span class="keyword">function</span>(<span class="params">newValues, oldValues</span>) </span>&#123;</div><div class="line">    <span class="built_in">console</span>.log(newValues, oldValues);</div><div class="line">&#125;);</div></pre></td></tr></table></figure><p><img src="/image/2018-05-21.4.png" alt=""><br><img src="/image/2018-05-21.5.png" alt=""><br><img src="/image/2018-05-21.6.png" alt=""></p><h2 id="watchCollection-obj-listener"><a href="#watchCollection-obj-listener" class="headerlink" title="$watchCollection(obj, listener)"></a>$watchCollection(obj, listener)</h2><p><code>$watchCollection</code>也是scope上的一个函数，同样为<code>$watch</code>的扩展。他可以监听一个对象，当对象中的任一个属性发生改变额时候，都会被监听到。</p><blockquote><p><code>obj</code> 部分同样可以是String或是function。</p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">$scope.people = &#123;</div><div class="line">    name: <span class="string">'zhangsan'</span>,</div><div class="line">    sex: <span class="string">'男'</span></div><div class="line">&#125;;</div><div class="line">$scope.dataCount = <span class="number">0</span>;</div><div class="line"></div><div class="line">$scope.$watchCollection(<span class="string">'people'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">newValue</span>) </span>&#123;</div><div class="line">    $scope.dataCount = $scope.dataCount + <span class="number">1</span>;</div><div class="line">&#125;);</div></pre></td></tr></table></figure><p><img src="/image/2018-05-21.7.png" alt=""><br><img src="/image/2018-05-21.8.png" alt=""></p><p>这个方法的功能跟使用<code>$watch</code>的第三个参数是一样的效果：当<code>$watch</code>的第三个参数为true的时候，就会实现这样的效果。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$scope.$watch(<span class="string">'people'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">newValue</span>) </span>&#123;&#125;, <span class="literal">true</span>);</div></pre></td></tr></table></figure><p>上一次我们已经提到过了，在这里使用true，表示新旧值将使用<code>angular.equals</code>来进行判等。在官方文档中有这么一句话：</p><blockquote><p>Both objects or values are of the same type and <code>all of their properties</code> are equal by comparing them with angular.equals.</p></blockquote><p>可以看到，这里的判等需要每个属性都相等。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>灵活的使用$watch以及相关的方法，会使你的展现的功能富有趣味，富有灵活性。</p><p><strong> 官方参考：<a href="https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch" target="_blank" rel="external">https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch</a></strong></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;上次介绍了两种&lt;code&gt;$watch&lt;/code&gt;的用法，今天在跟大家分享另外的几种用法。&lt;/p&gt;
    
    </summary>
    
    
      <category term="angularjs" scheme="http://yoursite.com/tags/angularjs/"/>
    
  </entry>
  
  <entry>
    <title>Angularjs中的$watch</title>
    <link href="http://yoursite.com/2018/05/19/angular-watch/"/>
    <id>http://yoursite.com/2018/05/19/angular-watch/</id>
    <published>2018-05-19T10:44:33.000Z</published>
    <updated>2018-05-19T13:22:25.540Z</updated>
    
    <content type="html"><![CDATA[<p>$watch 是在angularjs中常用的一个方法，他可以监听页面中的元素，在他们发生变化的时候，做出相应的变化。今天简单介绍一下我使用的两种用法。</p><a id="more"></a><h2 id="监听一个对象"><a href="#监听一个对象" class="headerlink" title="监听一个对象"></a>监听一个对象</h2><p>先来看一下他的基本用法：</p><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$watch(string, function(), [optional]);</div></pre></td></tr></table></figure><p>可以看到上面有三个参数，第一个是我们要监听的对象，他以字符串的方式呈现；</p><p>第二个参数是一个回调函数，他是我们在监听到变化是做的动作。他有三个参数：newValue，oldValue，scope。看名字就能知道这三个参数的含义：新值，旧值，当前作用域。</p><p>第三个参数是一个可选项，他是一个布尔值，使用<code>angular.equals</code>来比较对象，默认是false。</p><p>示例代码：</p><p>html部分：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">...</div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">ng-repeat</span>=<span class="string">'item in items'</span>&gt;</span>  </div><div class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;item.title&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span>  </div><div class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">ng-model</span>=<span class="string">'item.quantity'</span>&gt;</span>    </div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">...</div></pre></td></tr></table></figure><p>js部分：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">$scope.items = [</div><div class="line">&#123; <span class="attr">title</span>: <span class="string">'西瓜'</span>, <span class="attr">quantity</span>: <span class="number">8</span>, <span class="attr">price</span>: <span class="number">3.95</span> &#125;, </div><div class="line">&#123; <span class="attr">title</span>: <span class="string">'西红柿'</span>, <span class="attr">quantity</span>: <span class="number">17</span>, <span class="attr">price</span>: <span class="number">12.95</span> &#125;, </div><div class="line">&#123; <span class="attr">title</span>: <span class="string">'苹果'</span>, <span class="attr">quantity</span>: <span class="number">5</span>, <span class="attr">price</span>: <span class="number">6.95</span> &#125;];</div><div class="line"></div><div class="line">$scope.$watch(<span class="string">'items'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">newValue</span>) </span>&#123;</div><div class="line"><span class="keyword">if</span> (newValue) &#123;</div><div class="line"><span class="built_in">console</span>.log(<span class="string">"这是一个新值！"</span>);</div><div class="line"> &#125;</div><div class="line">&#125;, <span class="literal">true</span>);</div></pre></td></tr></table></figure><p><img src="/image/2018-05-19.1.png" alt=""><br><img src="/image/2018-05-19.2.png" alt=""><br><img src="/image/2018-05-19.3.png" alt=""><br>当我们改变输入框中的数字时，在控制台中就会出现<code>这是一个新值！</code>的字样。</p><h2 id="监视多个对象"><a href="#监视多个对象" class="headerlink" title="监视多个对象"></a>监视多个对象</h2><p>$watch 在监视两个对象的时候，后面的参数都和上面的相同，只有第一个是不一样的，变成了一个数组。</p><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$watch('[object1, object2]', function(newValue), [optional]);</div></pre></td></tr></table></figure><p>在监听两个变量的时候，我们看一下<code>newValue</code>是怎么个样子的：</p><p>下面的部分以项目中的指令为例：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">scope.$watch(<span class="string">'[instrumentType, discipline]'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">newValue</span>) </span>&#123;</div><div class="line">    <span class="built_in">console</span>.log(newValue);</div><div class="line">&#125;, <span class="literal">true</span>);</div></pre></td></tr></table></figure><p><img src="/image/2018-05-19.4.png" alt=""></p><p>监听了两个对象，反回来的当然也是两个对象了。那么我们就可在分别对这两个对象做一些事情，在第一个对象变化的时候和第二个对象变化的时候做不同的事情。</p><p>比如第一个变化的时候打印1，第二个变化的时候打印2：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">scope.$watch(<span class="string">'[instrumentType, discipline]'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">newValue</span>) </span>&#123;</div><div class="line">    <span class="keyword">if</span> (newValue[<span class="number">0</span>].selected &amp;&amp; newValue[<span class="number">0</span>].selected.id) &#123;</div><div class="line">    <span class="built_in">console</span>.log(<span class="string">"1"</span>);</div><div class="line">&#125;</div><div class="line"><span class="keyword">if</span> (newValue[<span class="number">1</span>].selected &amp;&amp; newValue[<span class="number">1</span>].selected.id) &#123;</div><div class="line"><span class="built_in">console</span>.log(<span class="string">"2"</span>);</div><div class="line">&#125;</div><div class="line">&#125;, <span class="literal">true</span>);</div></pre></td></tr></table></figure><p><img src="/image/2018-05-19.5.png" alt=""><br><img src="/image/2018-05-19.6.png" alt=""><br><img src="/image/2018-05-19.7.png" alt=""></p><p>这里就有人要问了，为什么我第一张打印的是2，而第二张打印的是1呢？原因是我们数组中对象的顺序与我们监听时设立的顺序是一样的：<code>[instrumentType, discipline]</code>。</p><h2 id="我的应用"><a href="#我的应用" class="headerlink" title="我的应用"></a>我的应用</h2><p>两个指令相互关联，但是又允许单独使用，所以就使用了上面的监听两个对象的做法。</p><p>效果展示：</p><p><img src="/image/2018-05-19.8.png" alt=""><br><img src="/image/2018-05-19.9.png" alt=""><br><img src="/image/2018-05-19.10.png" alt=""></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>$watch是一个有趣且灵活的函数，当然$watch的用法还不止我所说的这几种，还有很多其他的用法。<strong> <a href="https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch" target="_blank" rel="external">参考网址</a> </strong></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;$watch 是在angularjs中常用的一个方法，他可以监听页面中的元素，在他们发生变化的时候，做出相应的变化。今天简单介绍一下我使用的两种用法。&lt;/p&gt;
    
    </summary>
    
    
      <category term="angularjs" scheme="http://yoursite.com/tags/angularjs/"/>
    
  </entry>
  
  <entry>
    <title>项目心得(六)</title>
    <link href="http://yoursite.com/2018/05/16/project-experience-6/"/>
    <id>http://yoursite.com/2018/05/16/project-experience-6/</id>
    <published>2018-05-16T12:33:40.000Z</published>
    <updated>2018-05-16T14:01:43.891Z</updated>
    
    <content type="html"><![CDATA[<p>版本更新，这是我最近反复遇到的问题。今天又一次遇到了需要照顾版本的问题。在这里记录一下。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>添加新的菜单，存在老版本，需要照顾老版本。</p><a id="more"></a><h2 id="解决过程"><a href="#解决过程" class="headerlink" title="解决过程"></a>解决过程</h2><h3 id="1-直接添加菜单"><a href="#1-直接添加菜单" class="headerlink" title="1.直接添加菜单"></a>1.直接添加菜单</h3><p>最开始没有考虑到版本的问题，所以直接添加了一个菜单。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 人员资质</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">addWebAppMenusPersonnel</span><span class="params">()</span> </span>&#123;</div><div class="line">...</div><div class="line"> WebAppMenu personnelSuperviseFileMenu = <span class="keyword">new</span> WebAppMenu();</div><div class="line">    personnelSuperviseFileMenu.setRouteName(<span class="string">"personnelSuperviseFile"</span>);</div><div class="line">    personnelSuperviseFileMenu.setParentRouteWebAppMenu(personnelMenu);</div><div class="line">    personnelSuperviseFileMenu.setParentWebAppMenu(personnelMenu);</div><div class="line">    personnelSuperviseFileMenu.setName(<span class="string">"监督抽查人员档案"</span>);</div><div class="line">    personnelSuperviseFileMenu.setWeight(<span class="number">300</span>);</div><div class="line">    personnelSuperviseFileMenu.setDescription(<span class="string">"人员资质管理监督抽查人员档案"</span>);</div><div class="line">    webAppMenus.add(personnelSuperviseFileMenu);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>但是，很明显这种方法有问题。</p><h3 id="2-使用版本号进行控制"><a href="#2-使用版本号进行控制" class="headerlink" title="2.使用版本号进行控制"></a>2.使用版本号进行控制</h3><p>参考了一下以前的解决办法，生成一个随机的版本号，然后在执行初始化的时候判断一下有没有这个版本，如果没有，将版本号存进数据库，然后添加新的菜单；如果有，直接跳过。</p><p>上面的代码没有变，在开始的时候添加一个版本判断：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">String batch3 = <span class="string">"M0xOM80H0UWKVvE5GpVUiAg1b1cnAw5j"</span>;</div><div class="line"><span class="keyword">if</span> (<span class="keyword">null</span> == migrationService.findByBatch(batch3)) &#123;</div><div class="line">isAdd = <span class="keyword">true</span>;   <span class="comment">// 有新数据需要添加</span></div><div class="line"></div><div class="line">    logger.info(<span class="string">"维护版本信息"</span>);</div><div class="line">    migrationService.saveByBatch(batch3);</div><div class="line"></div><div class="line">    logger.info(<span class="string">"人员资质功能新增"</span>);</div><div class="line">    <span class="keyword">this</span>.addWebAppMenusPersonnel();</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这样会出现问题，在进行测试的时候，本应该出现一百多条的数据，只出现了几十条。原因是什么呢？</p><p>因为我们在这里使用的还是<code>addWebAppMenusPersonnel()</code>这个方法，但是这个方法中的菜单我们已经在前面统一添加的时候添加过了一次，现在再添加一次，那么就会产生重复。初始化执行到这里发现有问题，就停止执行了，所以测试就会出现问题。</p><h3 id="3-最终解决"><a href="#3-最终解决" class="headerlink" title="3.最终解决"></a>3.最终解决</h3><p>既然不能重复添加，那我们就要将新添加的菜单放在另一个函数中来单独添加。</p><p>首先将定义一个全局变量：<code>personnelMenu</code>。这是由于这是个父类的菜单，他会在两个函数中被调用。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> WebAppMenu personnelMenu;</div></pre></td></tr></table></figure><p>然后定义一个函数，用来单独添加新的菜单，同时要删除原来人员资质中的相应菜单部分：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 人员资质功能新增</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addPersonnelFunction</span><span class="params">()</span> </span>&#123;</div><div class="line">    logger.info(<span class="string">"为原有人员资质管理添加监督抽查人员档案"</span>);</div><div class="line">    WebAppMenu personnelSuperviseFileMenu = <span class="keyword">new</span> WebAppMenu();</div><div class="line">    personnelSuperviseFileMenu.setRouteName(<span class="string">"personnelSuperviseFile"</span>);</div><div class="line">    personnelSuperviseFileMenu.setParentRouteWebAppMenu(personnelMenu);</div><div class="line">    personnelSuperviseFileMenu.setParentWebAppMenu(personnelMenu);</div><div class="line">    personnelSuperviseFileMenu.setName(<span class="string">"监督抽查人员档案"</span>);</div><div class="line">    personnelSuperviseFileMenu.setWeight(<span class="number">300</span>);</div><div class="line">    personnelSuperviseFileMenu.setDescription(<span class="string">"人员资质管理监督抽查人员档案(适用于管理部门)"</span>);</div><div class="line">    webAppMenus.add(personnelSuperviseFileMenu);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>最后调用新建的函数：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">String batch3 = <span class="string">"M0xOM80H0UWKVvE5GpVUiAg1b1cnAw5j"</span>;</div><div class="line"><span class="keyword">if</span> (<span class="keyword">null</span> == migrationService.findByBatch(batch3)) &#123;</div><div class="line">    isAdd = <span class="keyword">true</span>;   <span class="comment">// 有新数据需要添加</span></div><div class="line"></div><div class="line">    logger.info(<span class="string">"维护版本信息"</span>);</div><div class="line">    migrationService.saveByBatch(batch3);</div><div class="line"></div><div class="line">    logger.info(<span class="string">"人员资质功能新增"</span>);</div><div class="line">    <span class="keyword">this</span>.addPersonnelFunction();</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这样问题就解决了。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>随着系统的完善，我们肯定会对系统升级多次，对数据的维护就显得至关重要。很多时候我们不能手动取操作数据表来维护数据，所以维护数据的代码就少不了了。这就是我们要实现的自动维护：程序一启动，完全不用考虑数据的问题。这才是我们想要的效果。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;版本更新，这是我最近反复遇到的问题。今天又一次遇到了需要照顾版本的问题。在这里记录一下。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;添加新的菜单，存在老版本，需要照顾老版本。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>实现多对多的两种方式</title>
    <link href="http://yoursite.com/2018/05/12/manytomany/"/>
    <id>http://yoursite.com/2018/05/12/manytomany/</id>
    <published>2018-05-12T05:01:15.000Z</published>
    <updated>2018-05-12T06:00:10.347Z</updated>
    
    <content type="html"><![CDATA[<p>在项目中，实体关系有一种是多对多关系。在最近的项目中，我学习了两种维护多对多关系的方式，在这里与大家分享一下。</p><h2 id="场景描述"><a href="#场景描述" class="headerlink" title="场景描述"></a>场景描述</h2><p>两个实体，角色和菜单，关系多对多。使用：Jpa的<code>@ManyToMany</code>注解。</p><a id="more"></a><h2 id="一：简单实现"><a href="#一：简单实现" class="headerlink" title="一：简单实现"></a>一：简单实现</h2><p>第一种的实现方法就是在字段上简单使用多对多注解。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Role</span> <span class="keyword">implements</span> <span class="title">Serializable</span></span>&#123;</div><div class="line">    ...</div><div class="line">    <span class="meta">@ManyToMany</span></div><div class="line">    <span class="keyword">private</span> Set&lt;WebAppMenu&gt; webAppMenus = <span class="keyword">new</span> HashSet&lt;WebAppMenu&gt;();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line">...</div><div class="line">    <span class="meta">@ManyToMany</span></div><div class="line">    <span class="keyword">private</span> Set&lt;Role&gt; roles = <span class="keyword">new</span> HashSet&lt;&gt;();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>但是在使用这种方法的时候，还需要使用@ManyToMany注解的一个属性<code>mappedBy</code>，来声明维护中间表的一方。如果在这个时候不使用这个属性，就会出现生成两张中间表的现象。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenu</span> </span>&#123;</div><div class="line">...</div><div class="line">    <span class="meta">@ManyToMany</span>(mappedBy = <span class="string">"webAppMenus"</span>)</div><div class="line">    <span class="keyword">private</span> Set&lt;Role&gt; roles = <span class="keyword">new</span> HashSet&lt;&gt;();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这次我们在role这个字段上的@ManyTomany注解上使用mappedBy，将维护权交给对方，也就是说roles不能维护双方的关系，关系由WebAppMenus来维护。这样就只会生成一张中间表。</p><h2 id="二：中间表类"><a href="#二：中间表类" class="headerlink" title="二：中间表类"></a>二：中间表类</h2><p>这种方法我们会直接定义一个中间表实体，然后将多对多的双方都映射到这个表中，这样一来就不用关维护方到底是谁了。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@Table</span>(name = <span class="string">"web_app_menu_role"</span>)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenuRole</span> <span class="keyword">implements</span> <span class="title">Serializable</span></span>&#123;</div><div class="line">...</div><div class="line">    <span class="meta">@ManyToOne</span></div><div class="line">    <span class="meta">@JoinColumn</span>(name = <span class="string">"role_id"</span>, insertable = <span class="keyword">false</span>, updatable = <span class="keyword">false</span>)</div><div class="line">    <span class="keyword">protected</span> Role role;</div><div class="line"></div><div class="line">    <span class="meta">@ManyToOne</span></div><div class="line">    <span class="meta">@JoinColumn</span>(name = <span class="string">"web_app_menu_id"</span>, insertable = <span class="keyword">false</span>, updatable = <span class="keyword">false</span>)</div><div class="line">    <span class="keyword">protected</span> WebAppMenu webAppMenu;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这是我们定义的中间表类，在这里，中间表和另外的两个实体关系都是多对一的，然后在实体上声明一下表名（也就是我们的中间表）：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Table</span>(name = <span class="string">"web_app_menu_role"</span>)</div></pre></td></tr></table></figure><p>然后声明一下中间表中的字段名：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@JoinColumn</span>(name = <span class="string">"role_id"</span>, insertable = <span class="keyword">false</span>, updatable = <span class="keyword">false</span>)</div><div class="line"><span class="meta">@JoinColumn</span>(name = <span class="string">"web_app_menu_id"</span>, insertable = <span class="keyword">false</span>, updatable = <span class="keyword">false</span>)</div></pre></td></tr></table></figure><p>在我们的两个实体中，实现如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenu</span> </span>&#123;</div><div class="line">...</div><div class="line">    <span class="meta">@ManyToMany</span></div><div class="line">    <span class="meta">@JoinTable</span>(</div><div class="line">            name = <span class="string">"web_app_menu_role"</span>,</div><div class="line">            joinColumns = <span class="meta">@JoinColumn</span>(name = <span class="string">"web_app_menu_id"</span>),</div><div class="line">            inverseJoinColumns = <span class="meta">@JoinColumn</span>(name = <span class="string">"role_id"</span>)</div><div class="line">    )</div><div class="line">    <span class="keyword">private</span> Set&lt;Role&gt; roles = <span class="keyword">new</span> HashSet&lt;&gt;();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Role</span> <span class="keyword">implements</span> <span class="title">Serializable</span></span>&#123;</div><div class="line">    ...</div><div class="line">    <span class="meta">@ManyToMany</span></div><div class="line">    <span class="meta">@JoinTable</span>(</div><div class="line">            name = <span class="string">"web_app_menu_role"</span>,</div><div class="line">            joinColumns = <span class="meta">@JoinColumn</span>(name = <span class="string">"role_id"</span>),</div><div class="line">            inverseJoinColumns = <span class="meta">@JoinColumn</span>(name = <span class="string">"web_app_menu_id"</span>)</div><div class="line">    )</div><div class="line">    <span class="keyword">private</span> Set&lt;WebAppMenu&gt; webAppMenus = <span class="keyword">new</span> HashSet&lt;WebAppMenu&gt;();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>关联的实体中依然使用@ManyToMany注解，然后再使用@JoinTable注解，声明将这两个字段映射到中间表里，并对应上面的字段名。</p><p><strong> 友情参考：<a href="https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany" target="_blank" rel="external">https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany</a></strong></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在项目中，实体关系有一种是多对多关系。在最近的项目中，我学习了两种维护多对多关系的方式，在这里与大家分享一下。&lt;/p&gt;
&lt;h2 id=&quot;场景描述&quot;&gt;&lt;a href=&quot;#场景描述&quot; class=&quot;headerlink&quot; title=&quot;场景描述&quot;&gt;&lt;/a&gt;场景描述&lt;/h2&gt;&lt;p&gt;两个实体，角色和菜单，关系多对多。使用：Jpa的&lt;code&gt;@ManyToMany&lt;/code&gt;注解。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>项目心得(五)——抽象类</title>
    <link href="http://yoursite.com/2018/05/10/abstract-class/"/>
    <id>http://yoursite.com/2018/05/10/abstract-class/</id>
    <published>2018-05-10T08:21:36.000Z</published>
    <updated>2018-05-11T14:17:12.722Z</updated>
    
    <content type="html"><![CDATA[<p>在实际的项目中我们经常会遇到两个实体关系是多对多的，这个时候同长会有一张用来维护实体关系的中间表。这次我就遇到了一个多对多的问题，而且其中还掺杂了抽象类干扰。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>两个实体：角色和菜单，多对多关联，由一张中间表来维护。现在要修改其中其中菜单的关联，将菜单换成他的基类菜单。出现问题的位置：通过角色获取所有的菜单。</p><a id="more"></a><h2 id="解决过程"><a href="#解决过程" class="headerlink" title="解决过程"></a>解决过程</h2><p>修改实体对应的关系这个比较简单，但在进行查询操作的时候就出现了问题。我们都知道，在通过角色获取所有菜单的时候，必然要通过中间表来找到对应的菜单。这时候报错出现了：</p><p><img src="/image/2018-05-10.1.png" alt=""></p><p>可以看到，报错中说不能从元组中实例化<code>BaseWebAppMenu</code>这个类从。原因是什么呢?</p><p>中间Google了好多办法，但是都不行。最终找到了问题的原因：<strong>BaseWebAppMenu这个父类是一个抽象类，不能进行实例化。</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Query</span>(value = <span class="string">"SELECT new BaseWebAppMenu(w.baseWebAppMenu.id) FROM UserRole u, WebAppMenuRole w where w.role.id = u.role.id and u.user.id=?1"</span>)</div><div class="line"><span class="function">List&lt;BaseWebAppMenu&gt; <span class="title">findAllByUserId</span><span class="params">(Long userId)</span></span>;</div></pre></td></tr></table></figure><blockquote><p>这里简单看了一下什么是元组：一个容器对象，包含了多个对象，允许从容器中读取，不允许向里添加。</p></blockquote><p>在repository中，我们需要通过角色获取所有的菜单，这时候我们使用了<code>@Query</code>这个注解，它在执行查询的时候会返回一个元组，元组中的对象就是实例化的基本菜单，但是基本菜单又不能实例化，所以就报出了上面的错误。</p><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><p>解决的办法很简单，既然抽象类不能实例化，那么我们就不让他是抽象类不就行了。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>在这里我们虽然是成功的解决了问题，但是我们又不得不思考后面的问题：我们的历史数据怎么实现保存。所以，还是要权衡一下能不能使用这个办法。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在实际的项目中我们经常会遇到两个实体关系是多对多的，这个时候同长会有一张用来维护实体关系的中间表。这次我就遇到了一个多对多的问题，而且其中还掺杂了抽象类干扰。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;两个实体：角色和菜单，多对多关联，由一张中间表来维护。现在要修改其中其中菜单的关联，将菜单换成他的基类菜单。出现问题的位置：通过角色获取所有的菜单。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>SQL：判断数据表中字段是否存在</title>
    <link href="http://yoursite.com/2018/05/07/sql-check-if-exist/"/>
    <id>http://yoursite.com/2018/05/07/sql-check-if-exist/</id>
    <published>2018-05-07T12:24:39.000Z</published>
    <updated>2018-05-11T12:41:12.201Z</updated>
    
    <content type="html"><![CDATA[<p>最近的项目中，有个需求需要重新创建字段，但是老的版本已经上线，原来的数据我们不能给它破坏，所以就需要判断一下是否已经存在那个字段，如果不存在就新建一个，如果存在就什么也不做。</p><a id="more"></a><h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><p>解决这个问题的时候，google了不少的办法，但是没有成功。无论是使用<code>if</code>条件判断，还是使用<code>exist</code>函数的时候都会报错。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">if Not exists(<span class="keyword">select</span> * <span class="keyword">from</span> sysobjects <span class="keyword">where</span> <span class="keyword">id</span>=object_id(<span class="string">'tableName'</span>) <span class="keyword">and</span> <span class="keyword">name</span>=<span class="string">'columnName'</span> ) <span class="keyword">then</span></div><div class="line"><span class="keyword">begin</span> </div><div class="line">alert <span class="keyword">table</span> tableName <span class="keyword">add</span> columnName</div><div class="line"><span class="keyword">end</span>;</div></pre></td></tr></table></figure><p>这个时候会报出字段不存在的错，在执行<code>select</code>这条命令的时候，由于数据表中还没有columnName这个字段，也就不认识columnName，所以报错。</p><p>类似的，中间还出过几个错，在这里就不一一列举了。</p><h2 id="最终的解决办法"><a href="#最终的解决办法" class="headerlink" title="最终的解决办法"></a>最终的解决办法</h2><p>最后的解决办法是在一个mysql的官方讨论区里找到的。在这里先给出解法。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">SET</span> @dbname = <span class="keyword">DATABASE</span> ( );</div><div class="line"><span class="keyword">SET</span> @tablename = <span class="string">"tableName"</span>;</div><div class="line"><span class="keyword">SET</span> @columnname = <span class="string">"columnName"</span>;</div><div class="line"><span class="keyword">SET</span> @preparedStatement = (</div><div class="line"><span class="keyword">SELECT</span></div><div class="line"><span class="keyword">IF</span> (</div><div class="line">(</div><div class="line"><span class="keyword">SELECT</span></div><div class="line"><span class="keyword">COUNT</span>( * ) </div><div class="line"><span class="keyword">FROM</span></div><div class="line">INFORMATION_SCHEMA.COLUMNS </div><div class="line"><span class="keyword">WHERE</span></div><div class="line">( table_name = @tablename ) </div><div class="line"><span class="keyword">AND</span> ( table_schema = @dbname ) </div><div class="line"><span class="keyword">AND</span> ( column_name = @columnname ) </div><div class="line">) &gt; <span class="number">0</span>,</div><div class="line"><span class="string">"SELECT 1"</span>,</div><div class="line"><span class="keyword">CONCAT</span>( <span class="string">"ALTER TABLE "</span>, @tablename, <span class="string">" ADD "</span>, @columnname, <span class="string">" VARCHAR(31) not null;"</span> ) </div><div class="line">) </div><div class="line">);</div><div class="line"><span class="keyword">PREPARE</span> alterIfNotExists </div><div class="line"><span class="keyword">FROM</span></div><div class="line">@preparedStatement;</div><div class="line"><span class="keyword">EXECUTE</span> alterIfNotExists;</div><div class="line"><span class="keyword">DEALLOCATE</span> <span class="keyword">PREPARE</span> alterIfNotExists;</div></pre></td></tr></table></figure><p>下面我做下简单解释。</p><blockquote><p>1.首先，定义了三个变量，分别为数据库名，表名，字段名，这是后面会重复用到的，所以在这里进行定义。<br>2.然后定义了另一个变量，这个变量主要执行查找<code>select</code>，查找是否存在我们要添加的字段的相关记录。<br>3.最后是这个解法的最特别之处：定义一个预处理变量，这个变量就是处理上面我们的查找的那个变量，然后执行预处理。最后Deallocate一下，释放所使用的数据库资源</p></blockquote><h2 id="预处理语句"><a href="#预处理语句" class="headerlink" title="预处理语句"></a>预处理语句</h2><p>好了，问题解决了，但是肯定还是有疑惑的：什么是预处理语句呢？</p><p><strong> MySQL官方将<code>prepare</code>、<code>execute</code>、<code>deallocate</code>统称为<code>PREPARE STATEMENT</code>。我们称之为【预处理语句】</strong></p><p>预处理，顾名思义，预先处理。他会在sql执行之前进行语句解析，然后统一执行一次或多次。通过上面的例子我们可以看到，预处理其实非常简单。</p><p>笔者对sql研究较少，理解有限，所以在这里给出预处理的<a href="https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-prepared-statements.html" target="_blank" rel="external">官方参考</a>。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过这次编写sql语句，感受到了sql的博大，从最开始比较水比较基础的sql语句，到后面使用预处理，语句质量提升了一大步，对sql又产生了兴趣。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近的项目中，有个需求需要重新创建字段，但是老的版本已经上线，原来的数据我们不能给它破坏，所以就需要判断一下是否已经存在那个字段，如果不存在就新建一个，如果存在就什么也不做。&lt;/p&gt;
    
    </summary>
    
    
      <category term="mysql" scheme="http://yoursite.com/tags/mysql/"/>
    
  </entry>
  
  <entry>
    <title>Hibernate 实体映射的继承关系</title>
    <link href="http://yoursite.com/2018/05/07/entity-inhetitance/"/>
    <id>http://yoursite.com/2018/05/07/entity-inhetitance/</id>
    <published>2018-05-07T12:23:07.000Z</published>
    <updated>2018-05-11T12:29:01.248Z</updated>
    
    <content type="html"><![CDATA[<p>实体与实体之间有时候是有一定的关系的，他们中间的大部分字段是相同的，而相同的代码需要我们写两遍，这是我们所不能忍受的，所以就有了继承，抽象出一个公共的父类，将相同的部分放在其中。而我们今天要说的<code>Hibernate</code> 的映射策略，是针对实体与数据表的关系说的。</p><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>两个系统，他们公用同一个后台。每个系统都有一个菜单类，现在两个菜单类实体的属性基本相同，需要用实体继承来实现。</p><a id="more"></a><h2 id="策略一：单表映射（single）"><a href="#策略一：单表映射（single）" class="headerlink" title="策略一：单表映射（single）"></a>策略一：单表映射（single）</h2><h3 id="描述"><a href="#描述" class="headerlink" title="描述"></a>描述</h3><p><code>单表映射</code>，顾名思义，只有一张表。它表示父类和继承它的子类共同使用一张数据表，然后另设一个字段，用来区分不同的实体。</p><h3 id="用法演示"><a href="#用法演示" class="headerlink" title="用法演示"></a>用法演示</h3><p>父类：</p><p>在父类中使用注解<code>@Inheritance</code>来声明这是继承的父类，然后在参数中定义继承的策略：单表继承<code>SINGLE_TABLE</code>。</p><p>使用注解<code>@DiscriminatorColumn</code>来生成一个新的字段，用来区别两个不同的子类。参数为字段的名字。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@Table</span>(name = <span class="string">"web_app_menu"</span>)       </div><div class="line"><span class="meta">@Inheritance</span>(strategy = InheritanceType.SINGLE_TABLE)   </div><div class="line"><span class="meta">@DiscriminatorColumn</span>(name = <span class="string">"DB_TYPE"</span>)      </div><div class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line">    <span class="comment">// 省略具体内容</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>子类：</p><p>在子类中，只需要通过注解<code>@DiscriminatorValue</code>来设置自己对应的用来区分的字段的名字。然后继承父类就行了。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@DiscriminatorValue</span>(<span class="string">"web_app_menu"</span>)    </div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@DiscriminatorValue</span>(<span class="string">"automation"</span>)   </div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AutomationWebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>最后会生成类似下面的表结构：</p><p><img src="/image/2018-05-11.1.png" alt=""></p><h2 id="策略二：Joined策略"><a href="#策略二：Joined策略" class="headerlink" title="策略二：Joined策略"></a>策略二：Joined策略</h2><h3 id="描述-1"><a href="#描述-1" class="headerlink" title="描述"></a>描述</h3><p>这种策略从字面上来看：加入，加盟。它的意思就是父类和子类都各自生成数据表，但是，父类的数据表中只有公共的字段，子类的数据表中只有扩展的字段。你生成你的字段，我生成我的字段，然后我们合起来就是完整的表了。</p><h3 id="用法演示-1"><a href="#用法演示-1" class="headerlink" title="用法演示"></a>用法演示</h3><p>父类：</p><p>父类中只需要通过<code>@Inheritance</code>注解来声明这是父类，然后策略为：<code>JOINED</code>。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@Inheritance</span>(strategy = InheritanceType.JOINED)   </div><div class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line">    <span class="meta">@Id</span></div><div class="line">    <span class="meta">@GeneratedValue</span>(strategy = GenerationType.AUTO)</div><div class="line">    <span class="keyword">private</span> Long id;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String name;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String pinyin;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String description;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> isAbstract = <span class="keyword">false</span>;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> Boolean status = <span class="keyword">true</span>;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String remark;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> Boolean isShow = <span class="keyword">true</span>;</div><div class="line"></div><div class="line">    <span class="comment">// 省略相关函数</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>子类：</p><p>由于需要对应不同的数据表，而又没有重新定义主键，所以需要使用<code>@PrimaryKeyJoinColumn</code>注解来声明一下主键。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@PrimaryKeyJoinColumn</span>(name = <span class="string">"web_app_menu_id"</span>)    </div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line"><span class="keyword">public</span> String head;</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@PrimaryKeyJoinColumn</span>(<span class="string">"automation_id"</span>)   </div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AutomationWebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line"><span class="keyword">public</span> String foot;</div><div class="line">&#125;</div></pre></td></tr></table></figure><h2 id="策略三：Table-per-Class策略"><a href="#策略三：Table-per-Class策略" class="headerlink" title="策略三：Table per Class策略"></a>策略三：Table per Class策略</h2><h3 id="描述-2"><a href="#描述-2" class="headerlink" title="描述"></a>描述</h3><p>这个策略也很好理解：一个类一张表嘛。而这个策略的特点是，每个子类单独创建数据表，并且拥有父类中的所有属性，数据也不会共享。</p><h3 id="用法演示-2"><a href="#用法演示-2" class="headerlink" title="用法演示"></a>用法演示</h3><p>父类：</p><p>父类的改动很小，只需要将上面的策略换成：<code>TABLE_PER_CLASS</code>就行了。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="meta">@Inheritance</span>(strategy = InheritanceType.TABLE_PER_CLASS)   </div><div class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line">    <span class="meta">@Id</span></div><div class="line">    <span class="meta">@GeneratedValue</span>(strategy = GenerationType.AUTO)</div><div class="line">    <span class="keyword">private</span> Long id;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String name;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String pinyin;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String description;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> isAbstract = <span class="keyword">false</span>;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> Boolean status = <span class="keyword">true</span>;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String remark;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> Boolean isShow = <span class="keyword">true</span>;</div><div class="line"></div><div class="line">    <span class="comment">// 省略相关函数</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>子类：</p><p>由于子类生成的表中会包含所有字段，所以子类什么也不需要做。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line"><span class="keyword">public</span> String head;</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Entity</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AutomationWebAppMenu</span> <span class="keyword">extends</span> <span class="title">BaseWebAppMenu</span> </span>&#123;</div><div class="line"><span class="keyword">public</span> String foot;</div><div class="line">&#125;</div></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><code>Hibernate</code>为我们解决了实体继承的问题，让我们不必再纠结实体与数据表的关系。但是这三种映射策略并不是什么时候都能使用的，还是需要看实际的项目中是什么样的情况，针对不同的情况使用不同的策略，才能发挥他最强大的功能。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;实体与实体之间有时候是有一定的关系的，他们中间的大部分字段是相同的，而相同的代码需要我们写两遍，这是我们所不能忍受的，所以就有了继承，抽象出一个公共的父类，将相同的部分放在其中。而我们今天要说的&lt;code&gt;Hibernate&lt;/code&gt; 的映射策略，是针对实体与数据表的关系说的。&lt;/p&gt;
&lt;h2 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h2&gt;&lt;p&gt;两个系统，他们公用同一个后台。每个系统都有一个菜单类，现在两个菜单类实体的属性基本相同，需要用实体继承来实现。&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
      <category term="JPA" scheme="http://yoursite.com/tags/JPA/"/>
    
      <category term="Hibernate" scheme="http://yoursite.com/tags/Hibernate/"/>
    
  </entry>
  
  <entry>
    <title>Docker 简记</title>
    <link href="http://yoursite.com/2018/04/29/docker/"/>
    <id>http://yoursite.com/2018/04/29/docker/</id>
    <published>2018-04-29T07:09:01.000Z</published>
    <updated>2018-04-29T10:31:24.496Z</updated>
    
    <content type="html"><![CDATA[<p>最近学习了由于团队的契机，在重新修改先前的一个项目时，需要统一配置环境，于是就选择了docker技术，所以有幸学习了docker技术，真是一门有趣的技术。好东西不能独享嘛，所以在这里跟大家分享一下。</p><a id="more"></a><h2 id="什么是Docker？"><a href="#什么是Docker？" class="headerlink" title="什么是Docker？"></a>什么是Docker？</h2><p><strong> Docker 在维基百科上的解释是：</strong></p><blockquote><p>Docker是一个<code>开放原始码</code>软体专案，让应用程式布署在<code>软体容器</code>下的工作可以自动化进行，借此在Linux作业系统上，提供一个额外的软体<code>抽象层</code>，以及<code>作业系统层虚拟化</code>的自动管理机制.</p></blockquote><p>emmmmm，很抽象。简单来说，Docker就是一个容器，就是一个小型的虚拟机，而他要比虚拟机更有优势，他体积更小，开启关闭更快。</p><h2 id="Docker有什么优势？"><a href="#Docker有什么优势？" class="headerlink" title="Docker有什么优势？"></a>Docker有什么优势？</h2><p>docker将同一类的项目都放到了一个容器中，那么我们就不需要为分类而苦恼了，每个不同的容器，都装了不同类的东西。在我们的项目中，不同的项目可能需要不同的环境，那么我们用docker将每一个项目所需的环境都放到不同的容器中，一来我们不用担心大家的环境不统一；二来一个人配置好环境，大家的环境就都配置好了，节省了时间。</p><h2 id="Docker安装"><a href="#Docker安装" class="headerlink" title="Docker安装"></a>Docker安装</h2><p>Windows和mac上的安装都比较简单，可以直接到<a href="https://www.docker.com/" target="_blank" rel="external">Docker官网</a>上下载，然后直接安装就行。下面我介绍一下在Ubuntu上的安装。</p><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>1.首先要检查一下你的<code>Linux</code>内核版本，需要大于3.10，当然，大部分都是满足的。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">uname -r</div></pre></td></tr></table></figure><p>2.更新源文件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo apt-get update</div></pre></td></tr></table></figure><p>3.安装https传输和CA证书</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo apt-get install apt-transport-https ca-certificates</div></pre></td></tr></table></figure><p>4.添加新的GPG</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D</div></pre></td></tr></table></figure><p>5.编辑source.list</p><p>在<code>/etc/apt/source.list</code>中添加新的仓库：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">deb https://apt.dockerproject.org/repo ubuntu-xenial main <span class="comment">#docker repository</span></div></pre></td></tr></table></figure><p>6.重新更新</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo apt-get update</div></pre></td></tr></table></figure><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>源文件添加完了，安装就简单了：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo apt-get install docker-engine</div></pre></td></tr></table></figure><h3 id="验证是否安装成功"><a href="#验证是否安装成功" class="headerlink" title="验证是否安装成功"></a>验证是否安装成功</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker -v</div></pre></td></tr></table></figure><h3 id="配置用户组"><a href="#配置用户组" class="headerlink" title="配置用户组"></a>配置用户组</h3><p>这里需要将自己添加到docker的用户组中，这样以后我们执行docker的命令时就不用输入sudo了。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo gpasswd a+x <span class="variable">$&#123;USER&#125;</span> docker</div></pre></td></tr></table></figure><p>重启docker服务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo service docker restart</div></pre></td></tr></table></figure><p><img src="/image/2018-04-29.1.png" alt=""></p><p>如果看到类似的版本信息，就说明你安装成功了。</p><h2 id="运行Docker服务"><a href="#运行Docker服务" class="headerlink" title="运行Docker服务"></a>运行Docker服务</h2><p>在这里给大家介绍几个常用的docker命令。</p><h3 id="1-docker-images"><a href="#1-docker-images" class="headerlink" title="1.docker images"></a>1.docker images</h3><p>这个命令会列出所有的镜像：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker images</div></pre></td></tr></table></figure><p><img src="/image/2018-04-29.2.png" alt=""></p><h3 id="2-docker-rmi-repository-image-id"><a href="#2-docker-rmi-repository-image-id" class="headerlink" title="2.docker rmi + repository/image id"></a>2.docker rmi + repository/image id</h3><p>这个命令会删除存在的镜像，后面用镜像的名字或是对应的id都可以：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker rmi nginx</div></pre></td></tr></table></figure><h3 id="3-docker-run"><a href="#3-docker-run" class="headerlink" title="3.docker run"></a>3.docker run</h3><p>运行镜像：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run nginx</div></pre></td></tr></table></figure><p><img src="/image/2018-04-29.3.png" alt=""></p><h3 id="4-docker-ps-a"><a href="#4-docker-ps-a" class="headerlink" title="4.docker ps [-a]"></a>4.docker ps [-a]</h3><p>列出所有的正在运行的容器，加上<code>-a</code>会将运行过的容器都显示出来：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker ps</div></pre></td></tr></table></figure><p><img src="/image/2018-04-29.4.png" alt=""></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker ps -a</div></pre></td></tr></table></figure><p><img src="/image/2018-04-29.5.png" alt=""></p><h3 id="5-docker-rm"><a href="#5-docker-rm" class="headerlink" title="5.docker rm"></a>5.docker rm</h3><p>删除容器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">docker rm 16f1af7c5b65</div><div class="line">``` </div><div class="line"></div><div class="line"><span class="comment">### 6.docker stop</span></div><div class="line"></div><div class="line">停止正在运行的容器</div><div class="line"></div><div class="line">```bash</div><div class="line">docker stop nginx</div></pre></td></tr></table></figure><h3 id="7-docker-pull"><a href="#7-docker-pull" class="headerlink" title="7.docker pull"></a>7.docker pull</h3><p>从远程仓库拉取镜像</p><h3 id="8-docker-build"><a href="#8-docker-build" class="headerlink" title="8.docker build"></a>8.docker build</h3><p>创建自己的镜像</p><h3 id="9-docker-commit"><a href="#9-docker-commit" class="headerlink" title="9.docker commit"></a>9.docker commit</h3><p>保存更改过的新镜像</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>相信docker这门技术以后会是团队合作的必备，也会成为我们这个大数据，云服务崛起的时代的一项必不可少的技术。</p><blockquote><p>相关参考：<a href="https://www.imooc.com/learn/867" target="_blank" rel="external">https://www.imooc.com/learn/867</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近学习了由于团队的契机，在重新修改先前的一个项目时，需要统一配置环境，于是就选择了docker技术，所以有幸学习了docker技术，真是一门有趣的技术。好东西不能独享嘛，所以在这里跟大家分享一下。&lt;/p&gt;
    
    </summary>
    
    
      <category term="docker" scheme="http://yoursite.com/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>java中的异步机制</title>
    <link href="http://yoursite.com/2018/04/10/java-asynchronous/"/>
    <id>http://yoursite.com/2018/04/10/java-asynchronous/</id>
    <published>2018-04-10T13:33:05.000Z</published>
    <updated>2018-04-19T06:21:24.754Z</updated>
    
    <content type="html"><![CDATA[<p>在最近的项目中,前台出现了一次500的异常,错误信息是 <code>read time out</code> .也就是说,调用的后台方法执行时间过长,然后在前台等待的时间里,没有方法没有执行结束,没有相应的相应,所以这时候,前后台的连接就断开了.而此次我解决问题选择的方法是在后台使用异步机制.</p><h2 id="为什么要使用异步"><a href="#为什么要使用异步" class="headerlink" title="为什么要使用异步"></a>为什么要使用异步</h2><p>简单来说,使用异步出于无奈.在同一个线程中,一个函数执行的时间过长,那么后面的函数就只能等着,那么我们就需要另外使用一个线程,将运行时间长的函数放到这个单独的线程中去执行.</p><a id="more"></a><h2 id="java-异步编程"><a href="#java-异步编程" class="headerlink" title="java 异步编程"></a>java 异步编程</h2><p>下面介绍两种 <code>java</code> 中的异步编程方式.</p><h3 id="Future方式的异步编程"><a href="#Future方式的异步编程" class="headerlink" title="Future方式的异步编程"></a><code>Future</code>方式的异步编程</h3><p><code>Future</code> 表示未来的某个异步计算的结果, 当我们向线程池提交任务的时候,就会获得这个对象. 然后可以使用 <code>get</code> 方法来获取计算完成的结果,并且只有在计算完成时才能使用.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">interface</span> <span class="title">ArchiveSearcher</span> </span>&#123; <span class="function">String <span class="title">search</span><span class="params">(String target)</span></span>; &#125;</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> </span>&#123;</div><div class="line">    ExecutorService executor = ...        <span class="comment">// 执行者,用来执行函数</span></div><div class="line">    ArchiveSearcher searcher = ...</div><div class="line">    <span class="function"><span class="keyword">void</span> <span class="title">showSearch</span><span class="params">(<span class="keyword">final</span> String target)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</div><div class="line">        Future&lt;String&gt; future = executor.submit(<span class="keyword">new</span> Callable&lt;String&gt;() &#123;</div><div class="line">            <span class="function"><span class="keyword">public</span> String <span class="title">call</span><span class="params">()</span> </span>&#123;</div><div class="line">                <span class="keyword">return</span> searcher.search(target);</div><div class="line">        &#125;&#125;);</div><div class="line">        displayOtherThings();           <span class="comment">// 在这里可以做一些其他的事情</span></div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            displayText(future.get());  <span class="comment">// 使用 future, 获取结果</span></div><div class="line">        &#125; <span class="keyword">catch</span> (ExecutionException ex) &#123; </div><div class="line">            cleanup(); </div><div class="line">            <span class="keyword">return</span>; </div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>可以看到,在这段代码中,我们先定义了一个执行者,他会执行未来的某个函数.然后我们定义了一个Future对象,他的值就是上面的执行者 <code>executor</code> 执行了 <code>call</code> 函数后的返回值.这个call函数中就是我们要执行的运行时间很长的函数.在他之后,这个函数或交给另一个线程去执行,而我们也不用等待这个函数执行完,可以去做一些其他的事情.最后,使用 <code>Future</code> 对象中的get方法,获取函数执行后的返回值.</p><blockquote><p><strong> 注意: </strong> 这里有可能会抛出一个执行异常,所以我们需要在这里使用try catch来处理一下异常.</p></blockquote><h3 id="CompletableFuture方式的异步编程"><a href="#CompletableFuture方式的异步编程" class="headerlink" title="CompletableFuture方式的异步编程"></a><code>CompletableFuture</code>方式的异步编程</h3><p>首先肯定就有人会问,有了Future,那为什么还要选择CompletableFuture这种异步编程的方式呢?</p><p>答案显而易见:<strong>Future存在缺陷</strong>.</p><blockquote><p>Future虽然实现了异步,但是他缺少通知机制,所以我们并不能知道函数什么时候执行结束.</p><p>使用阻塞,在<code>future.get()</code>的地方等待函数返回结果,但是这样就又成了同步的方式了.</p><p>使用<code>isDone</code>来进行轮询判断Future是否执行结束,但这样又会显得很多余,浪费很多的CPU.</p></blockquote><p>有问题必然就要解决,所以就有了我们的 <code>CompletableFuture</code> 的编程方式.</p><p><code>CompletableFuture</code> 这种异步编程的方式是在java8才出现的新的异步编程方式.他解决了一些在Future上存在的问题.使得java完整的实现了非阻塞方式的异步编程.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">CompletableFuture&lt;Void&gt; future = CompletableFuture.runAsync(() -&gt; &#123;</div><div class="line">    System.out.println(<span class="string">"Hello"</span>);</div><div class="line">&#125;);</div><div class="line"></div><div class="line"><span class="keyword">try</span> &#123;</div><div class="line">    future.get();</div><div class="line">&#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</div><div class="line">    e.printStackTrace();</div><div class="line">&#125; <span class="keyword">catch</span> (ExecutionException e) &#123;</div><div class="line">    e.printStackTrace();</div><div class="line">&#125;</div><div class="line"></div><div class="line">System.out.println(<span class="string">"CompletableFuture"</span>);</div></pre></td></tr></table></figure><p>这里我们可以看到,我们调用了<code>CompletableFuture</code>中的一个静态方法<code>runAsync()</code>来执行异步代码(这里会默认分配给他一个线程池), 他会返回一个没有返回值的<code>CompletableFuture</code>.</p><p>当然, <code>CompletableFuture</code> 当中还有很多的静态方法,可以获取没有返回值的,同样也可以获取有返回值的.这里就不一一介绍了.在最后我会给出链接,读者可自行学习.</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>虽然我们有异步编程的方式去解决函数执行时间长的问题,但是却不要首先想到这个执行办法,首先还是要看我们的函数时候能够减少数据库的IO操作,然后再去想是否应该使用异步编程.</p><p><strong> 官方参考: </strong></p><blockquote><p><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html" target="_blank" rel="external">https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html</a></p><p><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html" target="_blank" rel="external">https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在最近的项目中,前台出现了一次500的异常,错误信息是 &lt;code&gt;read time out&lt;/code&gt; .也就是说,调用的后台方法执行时间过长,然后在前台等待的时间里,没有方法没有执行结束,没有相应的相应,所以这时候,前后台的连接就断开了.而此次我解决问题选择的方法是在后台使用异步机制.&lt;/p&gt;
&lt;h2 id=&quot;为什么要使用异步&quot;&gt;&lt;a href=&quot;#为什么要使用异步&quot; class=&quot;headerlink&quot; title=&quot;为什么要使用异步&quot;&gt;&lt;/a&gt;为什么要使用异步&lt;/h2&gt;&lt;p&gt;简单来说,使用异步出于无奈.在同一个线程中,一个函数执行的时间过长,那么后面的函数就只能等着,那么我们就需要另外使用一个线程,将运行时间长的函数放到这个单独的线程中去执行.&lt;/p&gt;
    
    </summary>
    
    
      <category term="java" scheme="http://yoursite.com/tags/java/"/>
    
  </entry>
  
</feed>
