<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>loquy</title>
  
  
  <link href="http://www.loquy.cn/rss.xml" rel="self"/>
  
  <link href="http://www.loquy.cn/"/>
  <updated>2024-06-04T08:55:08.714Z</updated>
  <id>http://www.loquy.cn/</id>
  
  <author>
    <name>loquy</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>ASP.NET Core 使用教程</title>
    <link href="http://www.loquy.cn/posts/d02acb8d.html"/>
    <id>http://www.loquy.cn/posts/d02acb8d.html</id>
    <published>2024-05-27T08:37:28.000Z</published>
    <updated>2024-06-04T08:55:08.714Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一、应用启动"><a href="#一、应用启动" class="headerlink" title="一、应用启动"></a>一、应用启动</h2><p>在 ASP.NET Core 应用程序中，启动过程由主机（Host）负责，它负责配置应用程序并启动运行时环境。以下是 ASP.NET Core 应用程序的启动过程及相关概念：</p><h3 id="1-主机（Host）"><a href="#1-主机（Host）" class="headerlink" title="1. 主机（Host）"></a>1. 主机（Host）</h3><p>主机是 ASP.NET Core 应用程序的宿主环境，负责启动应用程序并提供运行时环境。主机可以是 Web 主机（如 IIS、Kestrel）、进程宿主（如 Console 应用）、自定义宿主等。</p><h3 id="2-应用程序启动"><a href="#2-应用程序启动" class="headerlink" title="2. 应用程序启动"></a>2. 应用程序启动</h3><p>ASP.NET Core 应用程序的启动过程通常在 <code>Program.cs</code> 文件中进行配置和定义。以下是一个典型的 <code>Program.cs</code> 文件示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Hosting;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.Hosting;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">MyApp</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-built_in">string</span>[] args</span>)</span><br>        &#123;<br>            CreateHostBuilder(args).Build().Run();<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IHostBuilder <span class="hljs-title">CreateHostBuilder</span>(<span class="hljs-params"><span class="hljs-built_in">string</span>[] args</span>)</span> =&gt;<br>            Host.CreateDefaultBuilder(args)<br>                .ConfigureWebHostDefaults(webBuilder =&gt;<br>                &#123;<br>                    webBuilder.UseStartup&lt;Startup&gt;();<br>                &#125;);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在 <code>Main</code> 方法中，通过调用 <code>CreateHostBuilder</code> 方法创建主机，并通过调用 <code>Build()</code> 方法构建主机，最后调用 <code>Run()</code> 方法启动应用程序。</p><h3 id="3-主机构建器（Host-Builder）"><a href="#3-主机构建器（Host-Builder）" class="headerlink" title="3. 主机构建器（Host Builder）"></a>3. 主机构建器（Host Builder）</h3><p><code>Host.CreateDefaultBuilder(args)</code> 方法创建了一个主机构建器，它会配置主机的默认行为。通常，主机构建器会加载配置、配置日志、设置主机环境等。</p><h3 id="4-Web-主机配置"><a href="#4-Web-主机配置" class="headerlink" title="4. Web 主机配置"></a>4. Web 主机配置</h3><p><code>ConfigureWebHostDefaults</code> 方法配置了 Web 主机的默认行为。在此处，可以配置 Web 主机的服务器（如 Kestrel）、应用程序配置、日志记录等。</p><h3 id="5-启动配置类（Startup-Class）"><a href="#5-启动配置类（Startup-Class）" class="headerlink" title="5. 启动配置类（Startup Class）"></a>5. 启动配置类（Startup Class）</h3><p><code>Startup</code> 类是 ASP.NET Core 应用程序的入口点，它包含了配置应用程序的逻辑。在 <code>ConfigureServices</code> 方法中，可以注册服务、配置中间件等；在 <code>Configure</code> 方法中，可以配置请求处理管道。</p><p>以下是一个典型的 <code>Startup.cs</code> 文件示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Builder;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Hosting;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.Configuration;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.Hosting;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">MyApp</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span><br>    &#123;<br>        <span class="hljs-keyword">public</span> IConfiguration Configuration &#123; <span class="hljs-keyword">get</span>; &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Startup</span>(<span class="hljs-params">IConfiguration configuration</span>)</span><br>        &#123;<br>            Configuration = configuration;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>        &#123;<br>            services.AddControllersWithViews();<br>            <span class="hljs-comment">// 添加其他服务配置</span><br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app, IWebHostEnvironment env</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">if</span> (env.IsDevelopment())<br>            &#123;<br>                app.UseDeveloperExceptionPage();<br>            &#125;<br>            <span class="hljs-keyword">else</span><br>            &#123;<br>                app.UseExceptionHandler(<span class="hljs-string">&quot;/Home/Error&quot;</span>);<br>            &#125;<br><br>            app.UseStaticFiles();<br><br>            app.UseRouting();<br><br>            app.UseAuthorization();<br><br>            app.UseEndpoints(endpoints =&gt;<br>            &#123;<br>                endpoints.MapControllerRoute(<br>                    name: <span class="hljs-string">&quot;default&quot;</span>,<br>                    pattern: <span class="hljs-string">&quot;&#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125;&quot;</span>);<br>            &#125;);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="6-启动过程总结"><a href="#6-启动过程总结" class="headerlink" title="6. 启动过程总结"></a>6. 启动过程总结</h3><ul><li>应用程序启动由主机负责，主机构建器配置默认行为。</li><li><code>ConfigureWebHostDefaults</code> 方法配置 Web 主机的默认行为，包括服务器、应用程序配置等。</li><li><code>Startup</code> 类是应用程序的入口点，负责配置应用程序的服务和请求处理管道。</li></ul><p>通过以上启动过程，ASP.NET Core 应用程序能够在启动时正确配置和准备好运行时环境，并通过 <code>Startup</code> 类中的逻辑处理请求和提供服务。</p><h2 id="二、依赖注入"><a href="#二、依赖注入" class="headerlink" title="二、依赖注入"></a>二、依赖注入</h2><p>依赖注入（Dependency Injection，简称 DI）是软件设计中的一种模式，通过将对象的依赖项（即其使用的其他对象）注入到该对象中，使得依赖关系更加明确和可控。ASP.NET Core 原生支持依赖注入，这使得服务的注册和管理变得简单和高效。</p><h3 id="1-依赖注入的核心概念"><a href="#1-依赖注入的核心概念" class="headerlink" title="1. 依赖注入的核心概念"></a>1. 依赖注入的核心概念</h3><ul><li><strong>服务（Service）</strong>：可以被应用程序中的其他部分使用的组件或对象。</li><li><strong>容器（Container）</strong>：用于管理服务的生命周期和解析服务依赖关系的对象。</li><li><strong>注册（Registration）</strong>：将服务类型和其实现类型添加到容器中。</li></ul><h3 id="2-服务的生命周期"><a href="#2-服务的生命周期" class="headerlink" title="2. 服务的生命周期"></a>2. 服务的生命周期</h3><p>在 ASP.NET Core 中，服务可以有以下几种生命周期：</p><ul><li><strong>瞬态（Transient）</strong>：每次请求服务时都会创建一个新的实例。适用于轻量级、无状态的服务。</li><li><strong>作用域（Scoped）</strong>：在一个请求的生命周期内创建一个实例。适用于需要在单个请求内保持状态的服务。</li><li><strong>单例（Singleton）</strong>：在应用程序的整个生命周期内只创建一个实例。适用于需要共享数据的服务。</li></ul><h3 id="3-自定义扩展方法注册-Services"><a href="#3-自定义扩展方法注册-Services" class="headerlink" title="3. 自定义扩展方法注册 Services"></a>3. 自定义扩展方法注册 Services</h3><p>为了简化服务的注册过程，可以创建自定义扩展方法。通过自定义扩展方法，可以将服务的注册逻辑集中在一起，使 <code>Startup.cs</code> 文件更加简洁。</p><p><strong>示例：ServiceCollectionExtensions.cs</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Services.Extensions</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ServiceCollectionExtensions</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddDependencyGroup</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span><br>        &#123;<br>            services.AddScoped&lt;IMyService, MyService&gt;();<br>            <span class="hljs-keyword">return</span> services;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在这个示例中，<code>AddDependencyGroup</code> 方法注册了一个作用域服务 <code>IMyService</code> 和其实现 <code>MyService</code>。</p><h3 id="4-在-Startup-cs-中注册服务"><a href="#4-在-Startup-cs-中注册服务" class="headerlink" title="4. 在 Startup.cs 中注册服务"></a>4. 在 Startup.cs 中注册服务</h3><p>在 <code>Startup.cs</code> 文件的 <code>ConfigureServices</code> 方法中，调用我们定义的扩展方法来注册服务。</p><p><strong>示例：Startup.cs</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 注册 Services</span><br>    services.AddDependencyGroup();<br><br>    <span class="hljs-comment">// 其他服务注册</span><br>&#125;<br></code></pre></td></tr></table></figure><p>通过这样的方法，我们可以将服务的注册逻辑分离到独立的扩展方法中，使得 <code>Startup.cs</code> 文件更加简洁。</p><h2 id="三、中间件"><a href="#三、中间件" class="headerlink" title="三、中间件"></a>三、中间件</h2><p>在 ASP.NET Core 中，中间件是构建 Web 应用程序的核心组件之一，提供了灵活的机制来处理请求和生成响应。中间件允许您在请求到达终端处理程序之前或之后执行自定义操作，例如日志记录、身份验证、路由和错误处理等。</p><h3 id="1-自定义中间件"><a href="#1-自定义中间件" class="headerlink" title="1. 自定义中间件"></a>1. 自定义中间件</h3><h4 id="1-1-编写基于约定的中间件"><a href="#1-1-编写基于约定的中间件" class="headerlink" title="1.1. 编写基于约定的中间件"></a>1.1. 编写基于约定的中间件</h4><p>ASP.NET Core 中间件的约定如下：</p><p><strong>公共构造函数</strong>:</p><ul><li>中间件类应具有一个公共构造函数，该构造函数至少包含一个 <code>RequestDelegate</code> 类型的参数。</li></ul><p><strong>Invoke 或 InvokeAsync 方法</strong>:</p><ul><li>中间件类应包含一个名为 <code>Invoke</code> 或 <code>InvokeAsync</code> 的公共方法。</li><li>该方法必须包含一个 <code>HttpContext</code> 类型的参数，并且必须返回一个 <code>Task</code>。</li></ul><p><strong>依赖注入（DI）支持</strong>:</p><ul><li>构造函数的其他参数可以通过依赖注入（DI）进行填充。</li><li><code>Invoke</code> 或 <code>InvokeAsync</code> 方法的其他参数也可以通过 DI 进行填充，可以是 <code>Transient</code>、<code>Scoped</code> 或 <code>Singleton</code> 类型的参数。</li></ul><p>下面是一个示例，展示了如何编写一个基于约定的中间件：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomMiddleware</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> RequestDelegate _next;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;CustomMiddleware&gt; _logger;<br><br>    <span class="hljs-comment">// 构造函数，接收 RequestDelegate 和其他依赖项</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomMiddleware</span>(<span class="hljs-params">RequestDelegate next, ILogger&lt;CustomMiddleware&gt; logger</span>)</span><br>    &#123;<br>        _next = next;<br>        _logger = logger;<br>    &#125;<br><br>    <span class="hljs-comment">// InvokeAsync 方法</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InvokeAsync</span>(<span class="hljs-params">HttpContext context</span>)</span><br>    &#123;<br>        _logger.LogInformation(<span class="hljs-string">&quot;Handling request: &quot;</span> + context.Request.Path);<br>        <br>        <span class="hljs-comment">// 在处理请求之前执行的逻辑</span><br>        <span class="hljs-keyword">await</span> _next(context);<br>        <br>        <span class="hljs-comment">// 在处理完请求之后执行的逻辑</span><br>        _logger.LogInformation(<span class="hljs-string">&quot;Finished handling request.&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>注册和使用基于约定的中间件</p><p>在 <code>Program.cs</code> 中注册并使用这个中间件：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><span class="hljs-keyword">var</span> app = builder.Build();<br><br>app.UseMiddleware&lt;CustomMiddleware&gt;();<br><br>app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello, World!&quot;</span>);<br>&#125;);<br><br>app.Run();<br></code></pre></td></tr></table></figure><h4 id="1-2-使用工厂模式的中间件"><a href="#1-2-使用工厂模式的中间件" class="headerlink" title="1.2. 使用工厂模式的中间件"></a>1.2. 使用工厂模式的中间件</h4><p>ASP.NET Core 还提供了一种使用工厂模式来激活中间件的方式，这种方式可以按请求创建中间件实例，提供更强的类型支持和灵活性。通过使用 <code>IMiddleware</code> 接口和中间件工厂，可以更好地控制中间件的生命周期和依赖项。</p><p> 创建实现 <code>IMiddleware</code> 接口的中间件:</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">FactoryActivatedMiddleware</span> : <span class="hljs-title">IMiddleware</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;FactoryActivatedMiddleware&gt; _logger;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">FactoryActivatedMiddleware</span>(<span class="hljs-params">ILogger&lt;FactoryActivatedMiddleware&gt; logger</span>)</span><br>    &#123;<br>        _logger = logger;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InvokeAsync</span>(<span class="hljs-params">HttpContext context, RequestDelegate next</span>)</span><br>    &#123;<br>        _logger.LogInformation(<span class="hljs-string">&quot;Handling request in factory activated middleware.&quot;</span>);<br><br>        <span class="hljs-comment">// 在处理请求之前执行的逻辑</span><br>        <span class="hljs-keyword">await</span> next(context);<br><br>        <span class="hljs-comment">// 在处理完请求之后执行的逻辑</span><br>        _logger.LogInformation(<span class="hljs-string">&quot;Finished handling request in factory activated middleware.&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p> 注册中间件:</p><p>在 <code>Program.cs</code> 中注册这个中间件：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><br><span class="hljs-comment">// 添加中间件到依赖注入容器</span><br>builder.Services.AddTransient&lt;FactoryActivatedMiddleware&gt;();<br><br><span class="hljs-keyword">var</span> app = builder.Build();<br><br><span class="hljs-comment">// 使用中间件</span><br>app.UseMiddleware&lt;FactoryActivatedMiddleware&gt;();<br><br>app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello, World!&quot;</span>);<br>&#125;);<br><br>app.Run();<br></code></pre></td></tr></table></figure><p>通过这种方式，中间件实例可以在每个请求时创建和销毁，从而避免了单实例中间件可能带来的问题。</p><h3 id="2-分析中间件代码"><a href="#2-分析中间件代码" class="headerlink" title="2. 分析中间件代码"></a>2. 分析中间件代码</h3><p>中间件本质上是一个实现 <code>RequestDelegate</code> 委托的组件，接收一个 <code>HttpContext</code> 对象作为参数，并返回一个 <code>Task</code>。中间件的核心逻辑通过这个委托实现。您可以根据具体需求编写自定义中间件，以实现各种功能，如日志记录、异常处理等。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomMiddleware</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> RequestDelegate _next;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomMiddleware</span>(<span class="hljs-params">RequestDelegate next</span>)</span><br>    &#123;<br>        _next = next;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InvokeAsync</span>(<span class="hljs-params">HttpContext context</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 在处理请求之前执行的逻辑</span><br>        <span class="hljs-keyword">await</span> _next(context);<br>        <span class="hljs-comment">// 在处理完请求之后执行的逻辑</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-使用-WebApplication-创建中间件管道"><a href="#3-使用-WebApplication-创建中间件管道" class="headerlink" title="3. 使用 WebApplication 创建中间件管道"></a>3. 使用 WebApplication 创建中间件管道</h3><p>您可以使用 <code>WebApplication</code> 类的 <code>Use</code> 方法来添加中间件到应用程序的请求处理管道中。中间件的顺序非常重要，它决定了它们在管道中的执行顺序。通常情况下，中间件按照它们添加到管道中的顺序依次执行。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><span class="hljs-keyword">var</span> app = builder.Build();<br><br>app.UseMiddleware&lt;CustomMiddleware&gt;();<br><br>app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello, World!&quot;</span>);<br>&#125;);<br><br>app.Run();<br></code></pre></td></tr></table></figure><h3 id="4-对请求管道进行短路"><a href="#4-对请求管道进行短路" class="headerlink" title="4. 对请求管道进行短路"></a>4. 对请求管道进行短路</h3><p>在 ASP.NET Core 中，当中间件决定不将请求传递给下一个中间件时，这被称为“让请求管道短路”。短路通常是必要的，因为它可以避免不必要的工作，从而提高性能。例如，静态文件中间件可以处理对静态文件的请求，并终止管道的进一步处理，成为终端中间件。</p><h4 id="1-为什么需要短路"><a href="#1-为什么需要短路" class="headerlink" title="1. 为什么需要短路"></a>1. 为什么需要短路</h4><ol><li><strong>性能优化</strong>：避免不必要的中间件执行。例如，静态文件中间件可以直接返回文件内容，而不需要其他中间件处理。</li><li><strong>简化逻辑</strong>：确保特定条件下的请求得到适当处理，而无需经过所有中间件。</li><li><strong>安全性</strong>：确保在某些情况下请求不会到达不应该处理它们的中间件。</li></ol><h4 id="2-示例：静态文件中间件"><a href="#2-示例：静态文件中间件" class="headerlink" title="2. 示例：静态文件中间件"></a>2. 示例：静态文件中间件</h4><p>以下示例展示了静态文件中间件如何短路请求管道：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><span class="hljs-keyword">var</span> app = builder.Build();<br><br>app.UseStaticFiles(); <span class="hljs-comment">// 静态文件中间件</span><br><br>app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello, World!&quot;</span>);<br>&#125;);<br><br>app.Run();<br></code></pre></td></tr></table></figure><p>在这个示例中，如果请求匹配一个静态文件（例如 CSS 或图像），<code>UseStaticFiles</code> 中间件会处理请求并短路管道，不会调用后续的中间件。</p><h4 id="3-确保短路后正确处理"><a href="#3-确保短路后正确处理" class="headerlink" title="3. 确保短路后正确处理"></a>3. 确保短路后正确处理</h4><p>如果中间件决定短路请求，它应该确保响应已正确生成并发送到客户端。调用 <code>next.Invoke</code> 之后进行响应处理时要特别小心，因为在响应已经启动后，修改响应头或状态码会引发异常。</p><h4 id="4-示例：条件短路"><a href="#4-示例：条件短路" class="headerlink" title="4. 示例：条件短路"></a>4. 示例：条件短路</h4><p>以下示例展示了如何在自定义中间件中实现条件短路：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomMiddleware</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> RequestDelegate _next;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomMiddleware</span>(<span class="hljs-params">RequestDelegate next</span>)</span><br>    &#123;<br>        _next = next;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InvokeAsync</span>(<span class="hljs-params">HttpContext context</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">if</span> (ShouldShortCircuit(context))<br>        &#123;<br>            context.Response.StatusCode = <span class="hljs-number">403</span>;<br>            <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Forbidden&quot;</span>);<br>            <span class="hljs-keyword">return</span>; <span class="hljs-comment">// 短路请求管道</span><br>        &#125;<br><br>        <span class="hljs-keyword">await</span> _next(context); <span class="hljs-comment">// 调用下一个中间件</span><br><br>        <span class="hljs-comment">// 注意：在调用 next 之后，避免修改响应头或状态码</span><br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-built_in">bool</span> <span class="hljs-title">ShouldShortCircuit</span>(<span class="hljs-params">HttpContext context</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 这里可以加入实际的短路条件，例如身份验证或其他检查</span><br>        <span class="hljs-keyword">return</span> !context.User.Identity.IsAuthenticated;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="51-警告：避免在响应启动后调用-next-Invoke"><a href="#51-警告：避免在响应启动后调用-next-Invoke" class="headerlink" title="51. 警告：避免在响应启动后调用 next.Invoke"></a>51. 警告：避免在响应启动后调用 <code>next.Invoke</code></h4><p>在向客户端发送响应期间和之后，请勿调用 <code>next.Invoke</code>。响应一旦启动，更改响应头或状态码将引发异常。以下是一些可能的结果：</p><ol><li><strong>协议冲突</strong>：例如，写入超过 <code>Content-Length</code> 指定的字节数。</li><li><strong>损坏正文格式</strong>：例如，将 HTML 页脚写入 CSS 文件中。</li></ol><h4 id="6-检查响应是否已启动"><a href="#6-检查响应是否已启动" class="headerlink" title="6. 检查响应是否已启动"></a>6. 检查响应是否已启动</h4><p><code>HttpContext.Response.HasStarted</code> 是一个有用的属性，它指示是否已经发送了响应头或写入了响应正文。可以在调用 <code>next.Invoke</code> 之前检查这个属性，确保在适当的时机执行必要的操作。</p><h4 id="7-示例：检查-HasStarted"><a href="#7-示例：检查-HasStarted" class="headerlink" title="7. 示例：检查 HasStarted"></a>7. 示例：检查 <code>HasStarted</code></h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomMiddleware</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> RequestDelegate _next;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomMiddleware</span>(<span class="hljs-params">RequestDelegate next</span>)</span><br>    &#123;<br>        _next = next;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InvokeAsync</span>(<span class="hljs-params">HttpContext context</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 执行一些逻辑，例如身份验证</span><br>        <span class="hljs-keyword">await</span> _next(context);<br><br>        <span class="hljs-keyword">if</span> (!context.Response.HasStarted)<br>        &#123;<br>            <span class="hljs-comment">// 在响应尚未开始时，安全地修改响应头或状态码</span><br>            context.Response.Headers.Add(<span class="hljs-string">&quot;X-Custom-Header&quot;</span>, <span class="hljs-string">&quot;Value&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">else</span><br>        &#123;<br>            <span class="hljs-comment">// 日志记录或其他操作</span><br>            Console.WriteLine(<span class="hljs-string">&quot;响应已经启动，无法修改响应头&quot;</span>);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="5-使用-Run-委托"><a href="#5-使用-Run-委托" class="headerlink" title="5. 使用 Run 委托"></a>5. 使用 Run 委托</h3><p><code>Run</code> 方法是 <code>WebApplication</code> 类中用于添加终端处理程序的方法。它接收一个 <code>RequestDelegate</code> 委托作为参数，表示处理请求的最终逻辑。您可以在这里编写应用程序的核心逻辑，例如返回页面或数据。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp">app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello, World!&quot;</span>);<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="6-灵活的中间件调用"><a href="#6-灵活的中间件调用" class="headerlink" title="6. 灵活的中间件调用"></a>6. 灵活的中间件调用</h3><p>ASP.NET Core 中的 <code>Use</code> 方法有多个重载版本，其中一个重载版本允许您指定一个委托，该委托接收 <code>HttpContext</code> 对象和一个 <code>RequestDelegate</code> 委托作为参数。这使得您可以在中间件中手动调用下一个中间件，从而实现更灵活的请求处理逻辑。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">app.Use(<span class="hljs-keyword">async</span> (context, next) =&gt;<br>&#123;<br>    <span class="hljs-comment">// 手动调用下一个中间件</span><br>    <span class="hljs-keyword">await</span> next(context);<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="7-确保中间件顺序正确"><a href="#7-确保中间件顺序正确" class="headerlink" title="7. 确保中间件顺序正确"></a>7. 确保中间件顺序正确</h3><p>中间件的顺序在 ASP.NET Core 中非常重要，因为它决定了请求和响应在管道中的执行顺序。每个中间件都依次处理请求，并有机会对请求进行操作，然后决定是否将请求传递给下一个中间件。</p><p>如果中间件的顺序不正确，可能会导致意外的行为，例如：</p><ul><li>无法进行适当的身份验证或授权。</li><li>无法正确处理静态文件。</li><li>缺少必要的错误处理。</li></ul><p>例如，身份验证中间件通常需要在授权中间件之前执行，以便在授权之前正确设置 <code>HttpContext.User</code>。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app</span>)</span><br>&#123;<br>    app.UseAuthentication(); <span class="hljs-comment">// 必须在 UseAuthorization 之前</span><br>    app.UseAuthorization();<br>    app.UseStaticFiles(); <span class="hljs-comment">// 必须在 UseRouting 之前</span><br>    app.UseRouting();<br>    app.UseEndpoints(endpoints =&gt;<br>    &#123;<br>        endpoints.MapControllers();<br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="示例：中间件顺序的重要性"><a href="#示例：中间件顺序的重要性" class="headerlink" title="示例：中间件顺序的重要性"></a>示例：中间件顺序的重要性</h4><p>以下示例展示了中间件顺序如何影响请求的处理：</p><ol><li>日志记录中间件</li><li>身份验证中间件</li><li>自定义中间件</li><li>终端中间件</li></ol><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app, IWebHostEnvironment env</span>)</span><br>&#123;<br>    <span class="hljs-keyword">if</span> (env.IsDevelopment())<br>    &#123;<br>        app.UseDeveloperExceptionPage(); <span class="hljs-comment">// 错误处理中间件应在管道的开头</span><br>    &#125;<br>    <span class="hljs-keyword">else</span><br>    &#123;<br>        app.UseExceptionHandler(<span class="hljs-string">&quot;/Home/Error&quot;</span>); <span class="hljs-comment">// 错误处理中间件应在管道的开头</span><br>        app.UseHsts();<br>    &#125;<br><br>    app.UseHttpsRedirection();<br>    app.UseStaticFiles(); <span class="hljs-comment">// 提供静态文件服务，应在路由中间件之前</span><br><br>    app.UseRouting();<br><br>    app.UseAuthentication(); <span class="hljs-comment">// 身份验证中间件</span><br>    app.UseAuthorization(); <span class="hljs-comment">// 授权中间件</span><br><br>    app.UseMiddleware&lt;CustomMiddleware&gt;(); <span class="hljs-comment">// 自定义中间件</span><br><br>    app.UseEndpoints(endpoints =&gt;<br>    &#123;<br>        endpoints.MapControllers(); <span class="hljs-comment">// 终端中间件，用于处理最终请求</span><br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="中间件执行顺序的示例"><a href="#中间件执行顺序的示例" class="headerlink" title="中间件执行顺序的示例"></a>中间件执行顺序的示例</h4><p>以下是一个更详细的示例，展示中间件执行顺序和请求处理的流程：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span><br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app, IWebHostEnvironment env</span>)</span><br>    &#123;<br>        app.Use(<span class="hljs-keyword">async</span> (context, next) =&gt;<br>        &#123;<br>            Console.WriteLine(<span class="hljs-string">&quot;Middleware 1: Before next()&quot;</span>);<br>            <span class="hljs-keyword">await</span> next.Invoke();<br>            Console.WriteLine(<span class="hljs-string">&quot;Middleware 1: After next()&quot;</span>);<br>        &#125;);<br><br>        app.Use(<span class="hljs-keyword">async</span> (context, next) =&gt;<br>        &#123;<br>            Console.WriteLine(<span class="hljs-string">&quot;Middleware 2: Before next()&quot;</span>);<br>            <span class="hljs-keyword">await</span> next.Invoke();<br>            Console.WriteLine(<span class="hljs-string">&quot;Middleware 2: After next()&quot;</span>);<br>        &#125;);<br><br>        app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>        &#123;<br>            Console.WriteLine(<span class="hljs-string">&quot;Terminal Middleware: Handling request&quot;</span>);<br>            <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello, World!&quot;</span>);<br>        &#125;);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>当您访问该应用时，控制台输出将如下所示：</p><figure class="highlight isbl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs isbl"><span class="hljs-variable">Middleware</span> <span class="hljs-number">1</span>: <span class="hljs-variable">Before</span> <span class="hljs-function"><span class="hljs-title">next</span>()</span><br><span class="hljs-variable">Middleware</span> <span class="hljs-number">2</span>: <span class="hljs-variable">Before</span> <span class="hljs-function"><span class="hljs-title">next</span>()</span><br><span class="hljs-variable">Terminal</span> <span class="hljs-variable">Middleware</span>: <span class="hljs-variable">Handling</span> <span class="hljs-variable">request</span><br><span class="hljs-variable">Middleware</span> <span class="hljs-number">2</span>: <span class="hljs-variable">After</span> <span class="hljs-function"><span class="hljs-title">next</span>()</span><br><span class="hljs-variable">Middleware</span> <span class="hljs-number">1</span>: <span class="hljs-variable">After</span> <span class="hljs-function"><span class="hljs-title">next</span>()</span><br></code></pre></td></tr></table></figure><p>这个输出展示了中间件的执行顺序。每个 <code>Use</code> 调用都会注册一个中间件组件，它们按照注册的顺序依次执行。</p><h3 id="8-对中间件管道进行分支"><a href="#8-对中间件管道进行分支" class="headerlink" title="8. 对中间件管道进行分支"></a>8. 对中间件管道进行分支</h3><p><code>Map</code> 扩展用作约定来创建管道分支。<code>Map</code> 基于给定请求路径的匹配项来创建请求管道分支。如果请求路径以给定路径开头，则执行分支。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><span class="hljs-keyword">var</span> app = builder.Build();<br><br>app.Map(<span class="hljs-string">&quot;/map1&quot;</span>, HandleMapTest1);<br>app.Map(<span class="hljs-string">&quot;/map2&quot;</span>, HandleMapTest2);<br><br>app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello from non-Map delegate.&quot;</span>);<br>&#125;);<br><br>app.Run();<br><br><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">HandleMapTest1</span>(<span class="hljs-params">IApplicationBuilder app</span>)</span><br>&#123;<br>    app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>    &#123;<br>        <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Map Test 1&quot;</span>);<br>    &#125;);<br>&#125;<br><br><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">HandleMapTest2</span>(<span class="hljs-params">IApplicationBuilder app</span>)</span><br>&#123;<br>    app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>    &#123;<br>        <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Map Test 2&quot;</span>);<br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="9-使用-MapWhen-进行条件分支"><a href="#9-使用-MapWhen-进行条件分支" class="headerlink" title="9. 使用 MapWhen 进行条件分支"></a>9. 使用 <code>MapWhen</code> 进行条件分支</h3><p><code>MapWhen</code> 基于给定谓词的结果创建请求管道分支。<code>Func&lt;HttpContext, bool&gt;</code> 类型的任何谓词均可用于将请求映射到管道的新分支。在以下示例中，谓词用于检测查询字符串变量是否存在。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><span class="hljs-keyword">var</span> app = builder.Build();<br><br>app.MapWhen(context =&gt; context.Request.Query.ContainsKey(<span class="hljs-string">&quot;branch&quot;</span>), HandleBranch);<br><br>app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello from non-Map delegate.&quot;</span>);<br>&#125;);<br><br>app.Run();<br><br><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">HandleBranch</span>(<span class="hljs-params">IApplicationBuilder app</span>)</span><br>&#123;<br>    app.Run(<span class="hljs-keyword">async</span> context =&gt;<br>    &#123;<br>        <span class="hljs-keyword">var</span> branchVer = context.Request.Query[<span class="hljs-string">&quot;branch&quot;</span>];<br>        <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">$&quot;Branch used = <span class="hljs-subst">&#123;branchVer&#125;</span>&quot;</span>);<br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="10-使用-UseWhen-进行条件分支"><a href="#10-使用-UseWhen-进行条件分支" class="headerlink" title="10. 使用 UseWhen 进行条件分支"></a>10. 使用 <code>UseWhen</code> 进行条件分支</h3><p><code>UseWhen</code> 也基于给定谓词的结果创建请求管道分支。与 <code>MapWhen</code> 不同的是，如果这个分支不发生短路或包含终端中间件，则会重新加入主管道。例如，以下示例中，如果请求中包含查询字符串变量，会记录其值并重新加入主管道。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><span class="hljs-keyword">var</span> app = builder.Build();<br><br>app.UseWhen(context =&gt; context.Request.Query.ContainsKey(<span class="hljs-string">&quot;branch&quot;</span>),<br>    appBuilder =&gt; HandleBranchAndRejoin(appBuilder));<br><br>app.Run(asynccontext =&gt;<br>&#123;<br>    <span class="hljs-keyword">await</span> context.Response.WriteAsync(<span class="hljs-string">&quot;Hello from non-Map delegate.&quot;</span>);<br>&#125;);<br><br>app.Run();<br><br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">HandleBranchAndRejoin</span>(<span class="hljs-params">IApplicationBuilder app</span>)</span><br>&#123;<br>    <span class="hljs-keyword">var</span> logger = app.ApplicationServices.GetRequiredService&lt;ILogger&lt;Program&gt;&gt;(); <br><br>    app.Use(<span class="hljs-keyword">async</span> (context, next) =&gt;<br>    &#123;<br>        <span class="hljs-keyword">var</span> branchVer = context.Request.Query[<span class="hljs-string">&quot;branch&quot;</span>];<br>        logger.LogInformation(<span class="hljs-string">&quot;Branch used = &#123;branchVer&#125;&quot;</span>, branchVer);<br><br>        <span class="hljs-comment">// Do work that doesn&#x27;t write to the Response.</span><br>        <span class="hljs-keyword">await</span> next();<br>        <span class="hljs-comment">// Do other work that doesn&#x27;t write to the Response.</span><br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="11-内置中间件"><a href="#11-内置中间件" class="headerlink" title="11. 内置中间件"></a>11. 内置中间件</h3><p>ASP.NET Core 附带了许多内置中间件组件，它们提供了各种功能，例如身份验证、授权、静态文件服务等。这些中间件的顺序和特性对于应用程序的正确运行至关重要。以下是一些常用的内置中间件及其作用：</p><ul><li><strong>身份验证</strong>：提供身份验证支持，通常在需要访问 <code>HttpContext.User</code> 之前执行。</li><li><strong>授权</strong>：提供授权支持，紧接在身份验证中间件之后执行。</li><li><strong>静态文件</strong>：为提供静态文件和目录浏览提供支持，通常作为终端中间件，如果请求与文件匹配，则为终端。</li><li><strong>MVC</strong>：使用 MVC&#x2F;Razor Pages 处理请求，通常作为终端中间件，如果请求与路由匹配，则为终端。</li><li><strong>开发者异常页面</strong>：生成一个页面，其中包含仅适用于开发环境的错误信息，通常在其他错误处理中间件之前执行。</li><li><strong>运行状况检查</strong>：检查应用程序及其依赖项的运行状况，通常作为终端中间件，如果请求与运行状况检查终结点匹配，则为终端。</li></ul><p>这些内置中间件在构建应用程序时提供了便利，但需要注意它们的顺序和条件以确保应用程序的正确运行。</p><h2 id="四、配置"><a href="#四、配置" class="headerlink" title="四、配置"></a>四、配置</h2><p>ASP.NET Core 提供了灵活且强大的配置系统，使开发者能够轻松地管理应用程序的配置设置。以下是关于 ASP.NET Core 中配置的一些关键概念和实现方法：</p><h3 id="1-配置源"><a href="#1-配置源" class="headerlink" title="1. 配置源"></a>1. 配置源</h3><p>ASP.NET Core 支持多种配置源，常见的包括：</p><ul><li><strong>文件</strong>：如 <code>appsettings.json</code>、<code>appsettings.&#123;Environment&#125;.json</code>。</li><li><strong>环境变量</strong>：用于存储敏感数据或环境特定的配置。</li><li><strong>命令行参数</strong>：在应用启动时传递参数。</li><li><strong>内存中</strong>：用于在代码中直接设置配置。</li><li><strong>用户机密</strong>：用于本地开发时存储敏感数据。</li><li><strong>Azure Key Vault</strong>：用于在 Azure 环境中存储机密。</li><li><strong>自定义配置源</strong>：可以实现 <code>IConfigurationSource</code> 接口来自定义配置源。</li></ul><h3 id="2-配置文件"><a href="#2-配置文件" class="headerlink" title="2. 配置文件"></a>2. 配置文件</h3><p>在 ASP.NET Core 项目中，最常见的配置文件是 <code>appsettings.json</code>。以下是一个示例配置文件：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;Logging&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>        <span class="hljs-attr">&quot;LogLevel&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>            <span class="hljs-attr">&quot;Default&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Information&quot;</span><span class="hljs-punctuation">,</span><br>            <span class="hljs-attr">&quot;Microsoft&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Warning&quot;</span><span class="hljs-punctuation">,</span><br>            <span class="hljs-attr">&quot;Microsoft.Hosting.Lifetime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Information&quot;</span><br>        <span class="hljs-punctuation">&#125;</span><br>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;AllowedHosts&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;*&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;ConnectionStrings&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>        <span class="hljs-attr">&quot;DefaultConnection&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Server=(localdb)\\mssqllocaldb;Database=aspnet-CoreApp;Trusted_Connection=True;MultipleActiveResultSets=true&quot;</span><br>    <span class="hljs-punctuation">&#125;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h3 id="3-配置加载顺序"><a href="#3-配置加载顺序" class="headerlink" title="3. 配置加载顺序"></a>3. 配置加载顺序</h3><p>ASP.NET Core 会按照以下顺序加载配置：</p><ol><li><strong>默认配置</strong>：应用程序的默认设置。</li><li><strong>应用配置文件</strong>：如 <code>appsettings.json</code> 和 <code>appsettings.&#123;Environment&#125;.json</code>。</li><li><strong>用户机密</strong>：仅在开发环境中加载。</li><li><strong>环境变量</strong>：覆盖前面的配置。</li><li><strong>命令行参数</strong>：覆盖所有前面的配置。</li></ol><h3 id="4-读取配置"><a href="#4-读取配置" class="headerlink" title="4. 读取配置"></a>4. 读取配置</h3><p>在 ASP.NET Core 中，通常使用 <code>IConfiguration</code> 接口来读取配置。以下是一个示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span><br>&#123;<br>    <span class="hljs-keyword">public</span> IConfiguration Configuration &#123; <span class="hljs-keyword">get</span>; &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Startup</span>(<span class="hljs-params">IConfiguration configuration</span>)</span><br>    &#123;<br>        Configuration = configuration;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 读取配置值</span><br>        <span class="hljs-keyword">var</span> mySetting = Configuration[<span class="hljs-string">&quot;MySetting&quot;</span>];<br>        <span class="hljs-keyword">var</span> connectionString = Configuration.GetConnectionString(<span class="hljs-string">&quot;DefaultConnection&quot;</span>);<br><br>        <span class="hljs-comment">// 将配置对象注入到依赖注入容器中</span><br>        services.Configure&lt;MySettings&gt;(Configuration.GetSection(<span class="hljs-string">&quot;MySettings&quot;</span>));<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="5-强类型配置"><a href="#5-强类型配置" class="headerlink" title="5. 强类型配置"></a>5. 强类型配置</h3><p>为了更好地管理配置，可以将配置绑定到强类型对象中。以下是一个示例：</p><h4 id="5-1-定义配置类"><a href="#5-1-定义配置类" class="headerlink" title="5.1 定义配置类"></a>5.1 定义配置类</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MySettings</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Setting1 &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> Setting2 &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="5-2-绑定配置"><a href="#5-2-绑定配置" class="headerlink" title="5.2 绑定配置"></a>5.2 绑定配置</h4><p>在 <code>Startup.cs</code> 中绑定配置：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>&#123;<br>    services.Configure&lt;MySettings&gt;(Configuration.GetSection(<span class="hljs-string">&quot;MySettings&quot;</span>));<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="5-3-使用配置"><a href="#5-3-使用配置" class="headerlink" title="5.3 使用配置"></a>5.3 使用配置</h4><p>通过依赖注入使用配置：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> MySettings _settings;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyService</span>(<span class="hljs-params">IOptions&lt;MySettings&gt; settings</span>)</span><br>    &#123;<br>        _settings = settings.Value;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">PrintSettings</span>()</span><br>    &#123;<br>        Console.WriteLine(<span class="hljs-string">$&quot;Setting1: <span class="hljs-subst">&#123;_settings.Setting1&#125;</span>&quot;</span>);<br>        Console.WriteLine(<span class="hljs-string">$&quot;Setting2: <span class="hljs-subst">&#123;_settings.Setting2&#125;</span>&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="6-环境特定的配置"><a href="#6-环境特定的配置" class="headerlink" title="6. 环境特定的配置"></a>6. 环境特定的配置</h3><p>ASP.NET Core 支持环境特定的配置文件，例如 <code>appsettings.Development.json</code> 和 <code>appsettings.Production.json</code>。在启动时，根据当前环境加载相应的配置文件。</p><h4 id="6-1-设置环境变量"><a href="#6-1-设置环境变量" class="headerlink" title="6.1 设置环境变量"></a>6.1 设置环境变量</h4><p>在启动配置文件中设置环境变量，例如 <code>launchSettings.json</code>：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>  <span class="hljs-attr">&quot;profiles&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;IIS Express&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>      <span class="hljs-attr">&quot;commandName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;IISExpress&quot;</span><span class="hljs-punctuation">,</span><br>      <span class="hljs-attr">&quot;environmentVariables&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>        <span class="hljs-attr">&quot;ASPNETCORE_ENVIRONMENT&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Development&quot;</span><br>      <span class="hljs-punctuation">&#125;</span><br>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;MyApp&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>      <span class="hljs-attr">&quot;commandName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Project&quot;</span><span class="hljs-punctuation">,</span><br>      <span class="hljs-attr">&quot;environmentVariables&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>        <span class="hljs-attr">&quot;ASPNETCORE_ENVIRONMENT&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Development&quot;</span><br>      <span class="hljs-punctuation">&#125;</span><br>    <span class="hljs-punctuation">&#125;</span><br>  <span class="hljs-punctuation">&#125;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h3 id="7-用户机密"><a href="#7-用户机密" class="headerlink" title="7. 用户机密"></a>7. 用户机密</h3><p>在开发环境中，用户机密用于存储敏感信息。使用 <code>dotnet user-secrets</code> 命令管理机密。</p><h4 id="7-1-启用用户机密"><a href="#7-1-启用用户机密" class="headerlink" title="7.1 启用用户机密"></a>7.1 启用用户机密</h4><p>在项目文件（<code>.csproj</code>）中添加用户机密支持：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">UserSecretsId</span>&gt;</span>aspnet-CoreApp-123456<span class="hljs-tag">&lt;/<span class="hljs-name">UserSecretsId</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span><br></code></pre></td></tr></table></figure><h4 id="7-2-添加用户机密"><a href="#7-2-添加用户机密" class="headerlink" title="7.2 添加用户机密"></a>7.2 添加用户机密</h4><p>使用命令行工具添加用户机密：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet user-secrets <span class="hljs-built_in">set</span> <span class="hljs-string">&quot;MySecret&quot;</span> <span class="hljs-string">&quot;secret_value&quot;</span><br></code></pre></td></tr></table></figure><h4 id="7-3-读取用户机密"><a href="#7-3-读取用户机密" class="headerlink" title="7.3 读取用户机密"></a>7.3 读取用户机密</h4><p>在应用程序中读取用户机密：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>&#123;<br>    <span class="hljs-keyword">var</span> mySecret = Configuration[<span class="hljs-string">&quot;MySecret&quot;</span>];<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="8-自定义配置源"><a href="#8-自定义配置源" class="headerlink" title="8. 自定义配置源"></a>8. 自定义配置源</h3><p>如果内置的配置源不能满足需求，可以实现自定义配置源。需要实现 <code>IConfigurationSource</code> 和 <code>IConfigurationProvider</code> 接口。</p><h4 id="8-1-实现自定义配置提供程序"><a href="#8-1-实现自定义配置提供程序" class="headerlink" title="8.1 实现自定义配置提供程序"></a>8.1 实现自定义配置提供程序</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomConfigurationProvider</span> : <span class="hljs-title">ConfigurationProvider</span><br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Load</span>()</span><br>    &#123;<br>        <span class="hljs-comment">// 加载配置数据</span><br>        Data = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt;<br>        &#123;<br>            &#123; <span class="hljs-string">&quot;CustomSetting:Setting1&quot;</span>, <span class="hljs-string">&quot;Value1&quot;</span> &#125;,<br>            &#123; <span class="hljs-string">&quot;CustomSetting:Setting2&quot;</span>, <span class="hljs-string">&quot;Value2&quot;</span> &#125;<br>        &#125;;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="8-2-实现自定义配置源"><a href="#8-2-实现自定义配置源" class="headerlink" title="8.2 实现自定义配置源"></a>8.2 实现自定义配置源</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomConfigurationSource</span> : <span class="hljs-title">IConfigurationSource</span><br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> IConfigurationProvider <span class="hljs-title">Build</span>(<span class="hljs-params">IConfigurationBuilder builder</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> CustomConfigurationProvider();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="8-3-注册自定义配置源"><a href="#8-3-注册自定义配置源" class="headerlink" title="8.3 注册自定义配置源"></a>8.3 注册自定义配置源</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span><br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Startup</span>(<span class="hljs-params">IConfiguration configuration</span>)</span><br>    &#123;<br>        Configuration = configuration;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> IConfiguration Configuration &#123; <span class="hljs-keyword">get</span>; &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">var</span> builder = <span class="hljs-keyword">new</span> ConfigurationBuilder();<br>        builder.Add(<span class="hljs-keyword">new</span> CustomConfigurationSource());<br>        <span class="hljs-keyword">var</span> configuration = builder.Build();<br><br>        <span class="hljs-keyword">var</span> customSetting1 = configuration[<span class="hljs-string">&quot;CustomSetting:Setting1&quot;</span>];<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>通过以上方法，开发者可以灵活地配置和管理 ASP.NET Core 应用程序的设置，确保应用程序能够根据不同的环境和需求进行正确的配置。</p><h2 id="五、日志"><a href="#五、日志" class="headerlink" title="五、日志"></a>五、日志</h2><p>在 ASP.NET Core 中，日志记录是一项重要的任务，它能够帮助开发人员在应用程序中追踪、调试和监控事件。本文将介绍 ASP.NET Core 内置的日志记录功能，以及如何安装、配置和使用第三方日志记录提供程序 NLog。</p><h3 id="1-内置日志记录提供程序"><a href="#1-内置日志记录提供程序" class="headerlink" title="1. 内置日志记录提供程序"></a>1. 内置日志记录提供程序</h3><h4 id="1-1-创建日志"><a href="#1-1-创建日志" class="headerlink" title="1.1 创建日志"></a>1.1 创建日志</h4><p>在 ASP.NET Core 中，可以通过内置的 <code>ILogger</code> 接口创建日志记录器。例如：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;MyController&gt; _logger;<br><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyController</span>(<span class="hljs-params">ILogger&lt;MyController&gt; logger</span>)</span><br>&#123;<br>    _logger = logger;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="1-2-配置日志记录"><a href="#1-2-配置日志记录" class="headerlink" title="1.2 配置日志记录"></a>1.2 配置日志记录</h4><p>ASP.NET Core 提供了灵活的日志记录配置选项，可以在 <code>appsettings.json</code> 文件中进行配置：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>  <span class="hljs-attr">&quot;Logging&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;LogLevel&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>      <span class="hljs-attr">&quot;Default&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Information&quot;</span><span class="hljs-punctuation">,</span><br>      <span class="hljs-attr">&quot;Microsoft&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Warning&quot;</span><span class="hljs-punctuation">,</span><br>      <span class="hljs-attr">&quot;Microsoft.Hosting.Lifetime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Information&quot;</span><br>    <span class="hljs-punctuation">&#125;</span><br>  <span class="hljs-punctuation">&#125;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h4 id="1-3-日志级别"><a href="#1-3-日志级别" class="headerlink" title="1.3 日志级别"></a>1.3 日志级别</h4><p>ASP.NET Core 内置了多个日志级别，包括 <code>Trace</code>、<code>Debug</code>、<code>Information</code>、<code>Warning</code>、<code>Error</code> 和 <code>Critical</code>。每个级别用于不同类型的日志消息，具体如下表所示：</p><table><thead><tr><th>LogLevel</th><th>值</th><th>方法</th><th>说明</th></tr></thead><tbody><tr><td>Trace</td><td>0</td><td>LogTrace</td><td>包含最详细的消息。</td></tr><tr><td>Debug</td><td>1</td><td>LogDebug</td><td>用于调试和开发。</td></tr><tr><td>Information</td><td>2</td><td>LogInformation</td><td>跟踪应用的常规流。</td></tr><tr><td>Warning</td><td>3</td><td>LogWarning</td><td>对于异常事件或意外事件。</td></tr><tr><td>Error</td><td>4</td><td>LogError</td><td>表示无法处理的错误和异常。</td></tr><tr><td>Critical</td><td>5</td><td>LogCritical</td><td>需要立即关注的失败。</td></tr></tbody></table><h4 id="1-4-日志消息模板"><a href="#1-4-日志消息模板" class="headerlink" title="1.4 日志消息模板"></a>1.4 日志消息模板</h4><p>每个日志消息都使用消息模板，可以包含要填充的参数占位符。例如：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">_logger.LogInformation(<span class="hljs-string">&quot;Getting item &#123;Id&#125;&quot;</span>, id);<br></code></pre></td></tr></table></figure><h4 id="1-5-记录异常"><a href="#1-5-记录异常" class="headerlink" title="1.5 记录异常"></a>1.5 记录异常</h4><p>记录异常时，可以将异常对象传递给日志记录器方法的重载版本：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">try</span><br>&#123;<br>    <span class="hljs-comment">// Some code that may throw an exception</span><br>&#125;<br><span class="hljs-keyword">catch</span> (Exception ex)<br>&#123;<br>    _logger.LogError(ex, <span class="hljs-string">&quot;An error occurred&quot;</span>);<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="1-6-默认日志级别"><a href="#1-6-默认日志级别" class="headerlink" title="1.6 默认日志级别"></a>1.6 默认日志级别</h4><p>如果未在配置中设置默认日志级别，则默认的日志级别为 <code>Information</code>。可以通过以下方式设置默认日志级别：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder();<br>builder.Logging.SetMinimumLevel(LogLevel.Warning);<br></code></pre></td></tr></table></figure><p>通常，建议在配置文件中指定日志级别，而不是在代码中指定。</p><h3 id="2-第三方日志记录提供程序之-NLog"><a href="#2-第三方日志记录提供程序之-NLog" class="headerlink" title="2. 第三方日志记录提供程序之 NLog"></a>2. 第三方日志记录提供程序之 NLog</h3><h4 id="2-1-安装"><a href="#2-1-安装" class="headerlink" title="2.1. 安装"></a>2.1. 安装</h4><p>要使用 NLog 作为日志记录提供程序，首先需要安装 NLog 包：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet add package NLog.Web.AspNetCore<br></code></pre></td></tr></table></figure><h4 id="2-2-创建-nlog-config-文件："><a href="#2-2-创建-nlog-config-文件：" class="headerlink" title="2.2. 创建 nlog.config 文件："></a>2.2. 创建 <code>nlog.config</code> 文件：</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;utf-8&quot;</span> ?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">nlog</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot;</span></span><br><span class="hljs-tag">      <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">      <span class="hljs-attr">autoReload</span>=<span class="hljs-string">&quot;true&quot;</span></span><br><span class="hljs-tag">      <span class="hljs-attr">internalLogLevel</span>=<span class="hljs-string">&quot;Info&quot;</span></span><br><span class="hljs-tag">      <span class="hljs-attr">internalLogFile</span>=<span class="hljs-string">&quot;c:\temp\internal-nlog-AspNetCore.txt&quot;</span>&gt;</span><br><br>  <span class="hljs-comment">&lt;!-- 启用 ASP.NET Core 布局渲染器 --&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">extensions</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">add</span> <span class="hljs-attr">assembly</span>=<span class="hljs-string">&quot;NLog.Web.AspNetCore&quot;</span>/&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">extensions</span>&gt;</span><br><br>  <span class="hljs-comment">&lt;!-- 日志写入目标 --&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">targets</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 用于记录所有日志消息的文件目标，包含基本细节 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">target</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">&quot;File&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;allfile&quot;</span> <span class="hljs-attr">fileName</span>=<span class="hljs-string">&quot;c:\temp\nlog-AspNetCore-all-$&#123;shortdate&#125;.log&quot;</span></span><br><span class="hljs-tag">            <span class="hljs-attr">layout</span>=<span class="hljs-string">&quot;$&#123;longdate&#125;|$&#123;event-properties:item=EventId:whenEmpty=0&#125;|$&#123;level:uppercase=true&#125;|$&#123;logger&#125;|$&#123;message&#125; $&#123;exception:format=tostring&#125;&quot;</span> /&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 用于记录自身日志消息的文件目标，使用额外的 Web 详情，使用一些 ASP.NET Core 渲染器 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">target</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">&quot;File&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;ownFile-web&quot;</span> <span class="hljs-attr">fileName</span>=<span class="hljs-string">&quot;c:\temp\nlog-AspNetCore-own-$&#123;shortdate&#125;.log&quot;</span></span><br><span class="hljs-tag">            <span class="hljs-attr">layout</span>=<span class="hljs-string">&quot;$&#123;longdate&#125;|$&#123;event-properties:item=EventId:whenEmpty=0&#125;|$&#123;level:uppercase=true&#125;|$&#123;logger&#125;|$&#123;message&#125; $&#123;exception:format=tostring&#125;|url: $&#123;aspnet-request-url&#125;|action: $&#123;aspnet-mvc-action&#125;&quot;</span> /&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 控制台目标，用于记录托管生命周期消息以改善 Docker/Visual Studio 启动检测 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">target</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">&quot;Console&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;lifetimeConsole&quot;</span> <span class="hljs-attr">layout</span>=<span class="hljs-string">&quot;$&#123;MicrosoftConsoleLayout&#125;&quot;</span> /&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">targets</span>&gt;</span><br><br>  <span class="hljs-comment">&lt;!-- 将日志记录器名称映射到目标的规则 --&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">rules</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 所有日志，包括来自 Microsoft 的日志 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;*&quot;</span> <span class="hljs-attr">minlevel</span>=<span class="hljs-string">&quot;Trace&quot;</span> <span class="hljs-attr">writeTo</span>=<span class="hljs-string">&quot;allfile&quot;</span> /&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 将托管生命周期消息输出到控制台目标，以加快启动检测 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;Microsoft.Hosting.Lifetime&quot;</span> <span class="hljs-attr">minlevel</span>=<span class="hljs-string">&quot;Info&quot;</span> <span class="hljs-attr">writeTo</span>=<span class="hljs-string">&quot;lifetimeConsole, ownFile-web&quot;</span> <span class="hljs-attr">final</span>=<span class="hljs-string">&quot;true&quot;</span> /&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 跳过非关键的 Microsoft 日志，仅记录自身日志（黑洞） --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;Microsoft.*&quot;</span> <span class="hljs-attr">maxlevel</span>=<span class="hljs-string">&quot;Info&quot;</span> <span class="hljs-attr">final</span>=<span class="hljs-string">&quot;true&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;System.Net.Http.*&quot;</span> <span class="hljs-attr">maxlevel</span>=<span class="hljs-string">&quot;Info&quot;</span> <span class="hljs-attr">final</span>=<span class="hljs-string">&quot;true&quot;</span> /&gt;</span><br>    <br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;*&quot;</span> <span class="hljs-attr">minlevel</span>=<span class="hljs-string">&quot;Trace&quot;</span> <span class="hljs-attr">writeTo</span>=<span class="hljs-string">&quot;ownFile-web&quot;</span> /&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">rules</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">nlog</span>&gt;</span><br><br></code></pre></td></tr></table></figure><p>归档策略</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 日志写入目标 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">targets</span>&gt;</span><br><span class="hljs-comment">&lt;!-- 用于记录自身日志消息的文件目标，使用额外的 Web 详情，使用一些 ASP.NET Core 渲染器 --&gt;</span><br><span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">- target：指定日志的目标类型，这里为“File”，表示日志将被记录到文件中。</span><br><span class="hljs-comment">- name：为此目标设置一个唯一的标识符，在日志规则中用于引用它。</span><br><span class="hljs-comment">- fileName：日志文件的路径和名称。`$&#123;basedir&#125;`是NLog中预定义的变量，表示应用程序的基目录。`$&#123;shortdate&#125;`插入当前日期，格式为 yyyy-MM-dd。</span><br><span class="hljs-comment">- layout：定义每个日志条目的格式。它包括各种占位符，如 `$&#123;longdate&#125;` 表示日期和时间，`$&#123;level&#125;` 表示日志级别，`$&#123;logger&#125;` 表示日志记录器名称，`$&#123;message&#125;` 表示日志消息，`$&#123;exception&#125;` 表示异常信息，`$&#123;aspnet-request-url&#125;` 表示 ASP.NET 请求的 URL，`$&#123;aspnet-mvc-action&#125;` 表示 MVC 动作名称。</span><br><span class="hljs-comment">- archiveFileName：指定归档日志文件的路径和名称格式。</span><br><span class="hljs-comment">- archiveAboveSize：当日志文件大小超过指定值时触发归档动作，这里是10485760字节（即10MB）。</span><br><span class="hljs-comment">- archiveEvery：指定归档频率，这里是每天归档一次。</span><br><span class="hljs-comment">- archiveNumbering：指定归档文件的编号方式，这里是“Rolling”，表示文件名中包含滚动编号。</span><br><span class="hljs-comment">- maxArchiveFiles：指定保留的归档文件数量，超出此数量的旧归档文件将被删除。</span><br><span class="hljs-comment">--&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">target</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">&quot;File&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;ownFile-web&quot;</span> <span class="hljs-attr">fileName</span>=<span class="hljs-string">&quot;$&#123;basedir&#125;/logs/APP-$&#123;shortdate&#125;.log&quot;</span></span><br><span class="hljs-tag"><span class="hljs-attr">layout</span>=<span class="hljs-string">&quot;$&#123;longdate&#125;|$&#123;event-properties:item=EventId:whenEmpty=0&#125;|$&#123;level:uppercase=true&#125;|$&#123;logger&#125;|$&#123;message&#125; $&#123;exception:format=tostring&#125;|url: $&#123;aspnet-request-url&#125;|action: $&#123;aspnet-mvc-action&#125;&quot;</span> </span><br><span class="hljs-tag"><span class="hljs-attr">archiveFileName</span>=<span class="hljs-string">&quot;$&#123;basedir&#125;/logs/archives/log.$&#123;shortdate&#125;.&#123;#&#125;.log&quot;</span></span><br><span class="hljs-tag"><span class="hljs-attr">archiveAboveSize</span>=<span class="hljs-string">&quot;10485760&quot;</span></span><br><span class="hljs-tag"><span class="hljs-attr">archiveEvery</span>=<span class="hljs-string">&quot;Day&quot;</span></span><br><span class="hljs-tag"><span class="hljs-attr">archiveNumbering</span>=<span class="hljs-string">&quot;Rolling&quot;</span></span><br><span class="hljs-tag"><span class="hljs-attr">maxArchiveFiles</span>=<span class="hljs-string">&quot;300&quot;</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">targets</span>&gt;</span><br></code></pre></td></tr></table></figure><h4 id="2-3-更新-program-cs"><a href="#2-3-更新-program-cs" class="headerlink" title="2.3. 更新 program.cs"></a>2.3. 更新 <code>program.cs</code></h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> NLog;<br><span class="hljs-keyword">using</span> NLog.Web;<br><br><span class="hljs-comment">// 提前初始化 NLog，以便在构建主机之前进行启动和异常记录</span><br><span class="hljs-keyword">var</span> logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();<br>logger.Debug(<span class="hljs-string">&quot;初始化主程序&quot;</span>);<br><br><span class="hljs-keyword">try</span><br>&#123;<br>    <span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);<br><br>    <span class="hljs-comment">// 将服务添加到容器中。</span><br>    builder.Services.AddControllersWithViews();<br><br>    <span class="hljs-comment">// NLog：设置 NLog 以进行依赖项注入</span><br>    builder.Logging.ClearProviders();<br>    builder.Host.UseNLog();<br><br>    <span class="hljs-keyword">var</span> app = builder.Build();<br><br>    <span class="hljs-comment">// 配置 HTTP 请求管道。</span><br>    <span class="hljs-keyword">if</span> (!app.Environment.IsDevelopment())<br>    &#123;<br>        app.UseExceptionHandler(<span class="hljs-string">&quot;/Home/Error&quot;</span>);<br>        <span class="hljs-comment">// 默认的 HSTS 值为 30 天。您可能希望针对生产环境更改此值，请参阅 https://aka.ms/aspnetcore-hsts。</span><br>        app.UseHsts();<br>    &#125;<br><br>    app.UseHttpsRedirection();<br>    app.UseStaticFiles();<br><br>    app.UseRouting();<br><br>    app.UseAuthorization();<br><br>    app.MapControllerRoute(<br>        name: <span class="hljs-string">&quot;default&quot;</span>,<br>        pattern: <span class="hljs-string">&quot;&#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125;&quot;</span>);<br><br>    app.Run();<br>&#125;<br><span class="hljs-keyword">catch</span> (Exception exception)<br>&#123;<br>    <span class="hljs-comment">// NLog：捕获设置错误</span><br>    logger.Error(exception, <span class="hljs-string">&quot;由于异常停止程序&quot;</span>);<br>    <span class="hljs-keyword">throw</span>;<br>&#125;<br><span class="hljs-keyword">finally</span><br>&#123;<br>    <span class="hljs-comment">// 确保在应用程序退出之前刷新和停止内部计时器/线程（避免 Linux 上的分段错误）</span><br>    NLog.LogManager.Shutdown();<br>&#125;<br><br></code></pre></td></tr></table></figure><h4 id="2-4-Microsoft-日志记录过滤器"><a href="#2-4-Microsoft-日志记录过滤器" class="headerlink" title="2.4. Microsoft 日志记录过滤器"></a>2.4. Microsoft 日志记录过滤器</h4><p>使用 <code>NLog 5.0</code> 时，默认情况下 <code>appsettings.json</code> 会忽略 <code>Microsoft</code> 日志记录筛选器。只需确保正确配置 <code>NLog</code> 配置规则即可。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">rules</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;System.*&quot;</span> <span class="hljs-attr">finalMinLevel</span>=<span class="hljs-string">&quot;Warn&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;Microsoft.*&quot;</span> <span class="hljs-attr">finalMinLevel</span>=<span class="hljs-string">&quot;Warn&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;Microsoft.Hosting.Lifetime*&quot;</span> <span class="hljs-attr">finalMinLevel</span>=<span class="hljs-string">&quot;Info&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logger</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;*&quot;</span> <span class="hljs-attr">minlevel</span>=<span class="hljs-string">&quot;Trace&quot;</span> <span class="hljs-attr">writeTo</span>=<span class="hljs-string">&quot;ownFile-web&quot;</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">rules</span>&gt;</span><br></code></pre></td></tr></table></figure><p>如果指定 <code>RemoveLoggerFactoryFilter = false</code> 了 <code>NLog</code> 日志记录提供程序选项，则它将使用 <code>appsettings.json</code> 中指定的筛选器。请注意，也可以在 <code>appsettings.json</code> 中指定 <code>NLog</code> 配置。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>  <span class="hljs-attr">&quot;Logging&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;LogLevel&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>      <span class="hljs-attr">&quot;Default&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Trace&quot;</span><span class="hljs-punctuation">,</span><br>      <span class="hljs-attr">&quot;Microsoft&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Warning&quot;</span><span class="hljs-punctuation">,</span><br>      <span class="hljs-attr">&quot;Microsoft.Hosting.Lifetime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Information&quot;</span><br>    <span class="hljs-punctuation">&#125;</span><br>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span><br>  <span class="hljs-attr">&quot;AllowedHosts&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;*&quot;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h4 id="2-5-使用"><a href="#2-5-使用" class="headerlink" title="2.5. 使用"></a>2.5. 使用</h4><p>在 ASP.NET Core 中，NLog 作为第三方日志记录提供程序，使用起来非常简单。只需按照上述配置步骤进行配置，然后就可以在代码中直接使用 <code>ILogger</code> 接口来记录日志，NLog 将自动将日志消息路由到相应的目的地。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">HomeController</span> : <span class="hljs-title">Controller</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;HomeController&gt; _logger;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HomeController</span>(<span class="hljs-params">ILogger&lt;HomeController&gt; logger</span>)</span><br>    &#123;<br>        _logger = logger;<br>        _logger.LogDebug(<span class="hljs-number">1</span>, <span class="hljs-string">&quot;NLog injected into HomeController&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Index</span>()</span><br>    &#123;<br>        _logger.LogInformation(<span class="hljs-string">&quot;Hello, this is the index!&quot;</span>);<br>        <span class="hljs-keyword">return</span> View();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="2-6-示例输出"><a href="#2-6-示例输出" class="headerlink" title="2.6. 示例输出"></a>2.6. 示例输出</h4><p>启动 ASP.NET Core 网站时，我们得到两个文件：</p><p>nlog-own-2024-05-29.log</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs log">2024-05-29 18:35:23.9930|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: https://localhost:7125 |url: |action: |Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync<br>2024-05-29 18:35:23.9930|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: http://localhost:5125 |url: |action: |Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync<br>2024-05-29 18:35:24.0084|0|INFO|Microsoft.Hosting.Lifetime|Application started. Press Ctrl+C to shut down. |url: |action: |Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted<br>2024-05-29 18:35:24.0084|0|INFO|Microsoft.Hosting.Lifetime|Hosting environment: Development |url: |action: |Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted<br>2024-05-29 18:35:24.0084|0|INFO|Microsoft.Hosting.Lifetime|Content root path: C:\Users\snakefoot\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\ |url: |action: |Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted<br>2024-05-29 18:35:25.6656|1|DEBUG|ASP.NetCore6_NLog_Web_Example.Controllers.HomeController|NLog injected into HomeController |url: https://localhost/|action: Index|ASP.NetCore6_NLog_Web_Example.Controllers.HomeController..ctor<br>2024-05-29 18:35:25.6656|0|INFO|ASP.NetCore6_NLog_Web_Example.Controllers.HomeController|Hello, this is the index! |url: https://localhost/|action: Index|ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index<br></code></pre></td></tr></table></figure><p>nlog-all-2024-05-29.log</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br></pre></td><td class="code"><pre><code class="hljs log">2024-05-29 18:35:15.1343|6|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets|Connection id &quot;0HMK16TVPK9JQ&quot; received FIN. <br>2024-05-29 18:35:15.1694|48|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16TVPK9JQ&quot; is closed. The last processed stream ID was 29. <br>2024-05-29 18:35:15.1694|7|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets|Connection id &quot;0HMK16TVPK9JQ&quot; sending FIN because: &quot;The client closed the connection.&quot; <br>2024-05-29 18:35:15.1805|2|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Connections|Connection id &quot;0HMK16TVPK9JQ&quot; stopped. <br>2024-05-29 18:35:23.6686|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/Home/Index.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/Home/Privacy.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/Shared/Error.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/Shared/_ValidationScriptsPartial.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/_ViewImports.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/_ViewStart.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|3|DEBUG|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Initializing Razor view compiler with compiled view: &#x27;/Views/Shared/_Layout.cshtml&#x27;. <br>2024-05-29 18:35:23.7133|12|DEBUG|Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory|Registered model binder providers, in the following order: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BinderTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ServicesModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.HeaderModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatingPointTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.EnumTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.DateTimeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.SimpleTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.CancellationTokenModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ByteArrayModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormFileModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormCollectionModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.KeyValuePairModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.DictionaryModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ArrayModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.CollectionModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinderProvider <br>2024-05-29 18:35:23.7746|1|DEBUG|Microsoft.Extensions.Hosting.Internal.Host|Hosting starting <br>2024-05-29 18:35:23.8067|63|INFO|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|User profile is available. Using &#x27;C:\Users\XXX\AppData\Local\ASP.NET\DataProtection-Keys&#x27; as key repository and Windows DPAPI to encrypt keys at rest. <br>2024-05-29 18:35:23.8067|37|DEBUG|Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository|Reading data from file &#x27;C:\Users\XXX\AppData\Local\ASP.NET\DataProtection-Keys\key-237c4f12-6703-4dd8-8e04-b904f77128d3.xml&#x27;. <br>2024-05-29 18:35:23.8067|37|DEBUG|Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository|Reading data from file &#x27;C:\Users\XXX\AppData\Local\ASP.NET\DataProtection-Keys\key-6c9a4248-29ef-409e-9349-fe5e287b835d.xml&#x27;. <br>2024-05-29 18:35:23.8067|37|DEBUG|Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository|Reading data from file &#x27;C:\Users\XXX\AppData\Local\ASP.NET\DataProtection-Keys\key-750f4bc0-7cc0-4ad8-809a-39972a95298d.xml&#x27;. <br>2024-05-29 18:35:23.8067|37|DEBUG|Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository|Reading data from file &#x27;C:\Users\XXX\AppData\Local\ASP.NET\DataProtection-Keys\key-dab65855-4eb4-4890-a09b-93b48ace1718.xml&#x27;. <br>2024-05-29 18:35:23.8067|18|DEBUG|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|Found key &#123;237c4f12-6703-4dd8-8e04-b904f77128d3&#125;. <br>2024-05-29 18:35:23.8067|18|DEBUG|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|Found key &#123;6c9a4248-29ef-409e-9349-fe5e287b835d&#125;. <br>2024-05-29 18:35:23.8067|18|DEBUG|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|Found key &#123;750f4bc0-7cc0-4ad8-809a-39972a95298d&#125;. <br>2024-05-29 18:35:23.8067|18|DEBUG|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|Found key &#123;dab65855-4eb4-4890-a09b-93b48ace1718&#125;. <br>2024-05-29 18:35:23.8272|13|DEBUG|Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver|Considering key &#123;dab65855-4eb4-4890-a09b-93b48ace1718&#125; with expiration date 2022-11-16 16:27:50Z as default key. <br>2024-05-29 18:35:23.8272|0|DEBUG|Microsoft.AspNetCore.DataProtection.TypeForwardingActivator|Forwarded activator type request from Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor, Microsoft.AspNetCore.DataProtection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 <br>2024-05-29 18:35:23.8272|51|DEBUG|Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor|Decrypting secret element using Windows DPAPI. <br>2024-05-29 18:35:23.8272|0|DEBUG|Microsoft.AspNetCore.DataProtection.TypeForwardingActivator|Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 <br>2024-05-29 18:35:23.8367|4|DEBUG|Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngCbcAuthenticatedEncryptorFactory|Opening CNG algorithm &#x27;AES&#x27; from provider &#x27;(null)&#x27; with chaining mode CBC. <br>2024-05-29 18:35:23.8367|3|DEBUG|Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngCbcAuthenticatedEncryptorFactory|Opening CNG algorithm &#x27;SHA256&#x27; from provider &#x27;(null)&#x27; with HMAC. <br>2024-05-29 18:35:23.8367|2|DEBUG|Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider|Using key &#123;dab65855-4eb4-4890-a09b-93b48ace1718&#125; as the default key. <br>2024-05-29 18:35:23.8367|65|DEBUG|Microsoft.AspNetCore.DataProtection.Internal.DataProtectionHostedService|Key ring with default key &#123;dab65855-4eb4-4890-a09b-93b48ace1718&#125; was loaded during application startup. <br>2024-05-29 18:35:23.9534|0|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer|Using development certificate: CN=localhost (Thumbprint: 3271A3360CD4E4DC9058F84E9FB3A1E651D0F7C9) <br>2024-05-29 18:35:23.9930|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: https://localhost:7125 <br>2024-05-29 18:35:23.9930|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: http://localhost:5125 <br>2024-05-29 18:35:24.0084|13|DEBUG|Microsoft.AspNetCore.Hosting.Diagnostics|Loaded hosting startup assembly ASP.NetCore6_NLog_Web_Example <br>2024-05-29 18:35:24.0084|13|DEBUG|Microsoft.AspNetCore.Hosting.Diagnostics|Loaded hosting startup assembly Microsoft.AspNetCore.Watch.BrowserRefresh <br>2024-05-29 18:35:24.0084|13|DEBUG|Microsoft.AspNetCore.Hosting.Diagnostics|Loaded hosting startup assembly Microsoft.WebTools.BrowserLink.Net <br>2024-05-29 18:35:24.0084|0|INFO|Microsoft.Hosting.Lifetime|Application started. Press Ctrl+C to shut down. <br>2024-05-29 18:35:24.0084|0|INFO|Microsoft.Hosting.Lifetime|Hosting environment: Development <br>2024-05-29 18:35:24.0084|0|INFO|Microsoft.Hosting.Lifetime|Content root path: C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\ <br>2024-05-29 18:35:24.0084|2|DEBUG|Microsoft.Extensions.Hosting.Internal.Host|Hosting started <br>2024-05-29 18:35:24.4292|39|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Connections|Connection id &quot;0HMK16UJ982TR&quot; accepted. <br>2024-05-29 18:35:24.4292|39|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Connections|Connection id &quot;0HMK16UJ982TQ&quot; accepted. <br>2024-05-29 18:35:24.4306|1|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Connections|Connection id &quot;0HMK16UJ982TQ&quot; started. <br>2024-05-29 18:35:24.4306|1|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Connections|Connection id &quot;0HMK16UJ982TR&quot; started. <br>2024-05-29 18:35:24.4533|6|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets|Connection id &quot;0HMK16UJ982TQ&quot; received FIN. <br>2024-05-29 18:35:24.4533|6|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets|Connection id &quot;0HMK16UJ982TR&quot; received FIN. <br>2024-05-29 18:35:25.5421|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/ - - <br>2024-05-29 18:35:25.5892|0|DEBUG|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|Wildcard detected, all requests with hosts will be allowed. <br>2024-05-29 18:35:25.5892|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:25.5892|4|DEBUG|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|The request path / does not match a supported file type <br>2024-05-29 18:35:25.6168|1001|DEBUG|Microsoft.AspNetCore.Routing.Matching.DfaMatcher|1 candidate(s) found for the request path &#x27;/&#x27; <br>2024-05-29 18:35:25.6198|1005|DEBUG|Microsoft.AspNetCore.Routing.Matching.DfaMatcher|Endpoint &#x27;ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example)&#x27; with route pattern &#x27;&#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125;&#x27; is valid for the request path &#x27;/&#x27; <br>2024-05-29 18:35:25.6198|1|DEBUG|Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware|Request matched endpoint &#x27;ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example)&#x27; <br>2024-05-29 18:35:25.6198|0|INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executing endpoint &#x27;ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example)&#x27; <br>2024-05-29 18:35:25.6595|3|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Route matched with &#123;action = &quot;Index&quot;, controller = &quot;Home&quot;&#125;. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Index() on controller ASP.NetCore6_NLog_Web_Example.Controllers.HomeController (ASP.NetCore6_NLog_Web_Example). <br>2024-05-29 18:35:25.6595|1|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Execution plan of authorization filters (in the following order): None <br>2024-05-29 18:35:25.6595|1|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Execution plan of resource filters (in the following order): Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter <br>2024-05-29 18:35:25.6595|1|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Execution plan of action filters (in the following order): Microsoft.AspNetCore.Mvc.Filters.ControllerActionFilter (Order: -2147483648), Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter (Order: -3000) <br>2024-05-29 18:35:25.6595|1|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Execution plan of exception filters (in the following order): None <br>2024-05-29 18:35:25.6595|1|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Execution plan of result filters (in the following order): Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter <br>2024-05-29 18:35:25.6656|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Resource Filter: Before executing OnResourceExecuting on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.6656|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Resource Filter: After executing OnResourceExecuting on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.6656|1|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executing controller factory for controller ASP.NetCore6_NLog_Web_Example.Controllers.HomeController (ASP.NetCore6_NLog_Web_Example) <br>2024-05-29 18:35:25.6656|1|DEBUG|ASP.NetCore6_NLog_Web_Example.Controllers.HomeController|NLog injected into HomeController <br>2024-05-29 18:35:25.6656|2|DEBUG|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executed controller factory for controller ASP.NetCore6_NLog_Web_Example.Controllers.HomeController (ASP.NetCore6_NLog_Web_Example) <br>2024-05-29 18:35:25.6656|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Action Filter: Before executing OnActionExecutionAsync on filter Microsoft.AspNetCore.Mvc.Filters.ControllerActionFilter. <br>2024-05-29 18:35:25.6656|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Action Filter: Before executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter. <br>2024-05-29 18:35:25.6656|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Action Filter: After executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter. <br>2024-05-29 18:35:25.6656|1|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executing action method ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example) - Validation state: Valid <br>2024-05-29 18:35:25.6656|0|INFO|ASP.NetCore6_NLog_Web_Example.Controllers.HomeController|Hello, this is the index! <br>2024-05-29 18:35:25.6831|2|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executed action method ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example), returned result Microsoft.AspNetCore.Mvc.ViewResult in 2.7721ms. <br>2024-05-29 18:35:25.6831|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Action Filter: Before executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter. <br>2024-05-29 18:35:25.6831|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Action Filter: After executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter. <br>2024-05-29 18:35:25.6831|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Action Filter: After executing OnActionExecutionAsync on filter Microsoft.AspNetCore.Mvc.Filters.ControllerActionFilter. <br>2024-05-29 18:35:25.6831|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Result Filter: Before executing OnResultExecuting on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.6831|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Result Filter: After executing OnResultExecuting on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.6831|4|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Before executing action result Microsoft.AspNetCore.Mvc.ViewResult. <br>2024-05-29 18:35:25.6831|1|DEBUG|Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine|View lookup cache miss for view &#x27;Index&#x27; in controller &#x27;Home&#x27;. <br>2024-05-29 18:35:25.6831|5|TRACE|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Located compiled view for view at path &#x27;/Views/Home/Index.cshtml&#x27;. <br>2024-05-29 18:35:25.6831|7|TRACE|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Could not find a file for view at path &#x27;/Views/Home/_ViewStart.cshtml&#x27;. <br>2024-05-29 18:35:25.6831|5|TRACE|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Located compiled view for view at path &#x27;/Views/_ViewStart.cshtml&#x27;. <br>2024-05-29 18:35:25.6831|7|TRACE|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Could not find a file for view at path &#x27;/_ViewStart.cshtml&#x27;. <br>2024-05-29 18:35:25.6960|1|INFO|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|Executing ViewResult, running view Index. <br>2024-05-29 18:35:25.6960|2|DEBUG|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|The view path &#x27;/Views/Home/Index.cshtml&#x27; was found in 9.3119ms. <br>2024-05-29 18:35:25.7393|1|DEBUG|Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine|View lookup cache miss for view &#x27;_Layout&#x27; in controller &#x27;Home&#x27;. <br>2024-05-29 18:35:25.7393|7|TRACE|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Could not find a file for view at path &#x27;/Views/Home/_Layout.cshtml&#x27;. <br>2024-05-29 18:35:25.7393|5|TRACE|Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler|Located compiled view for view at path &#x27;/Views/Shared/_Layout.cshtml&#x27;. <br>2024-05-29 18:35:25.7816|100|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Found the endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for address Microsoft.AspNetCore.Routing.RouteValuesAddress <br>2024-05-29 18:35:25.7899|102|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Successfully processed template &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; resulting in  and  <br>2024-05-29 18:35:25.7899|105|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Link generation succeeded for endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; with result / <br>2024-05-29 18:35:25.7899|100|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Found the endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for address Microsoft.AspNetCore.Routing.RouteValuesAddress <br>2024-05-29 18:35:25.7899|102|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Successfully processed template &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; resulting in  and  <br>2024-05-29 18:35:25.7899|105|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Link generation succeeded for endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; with result / <br>2024-05-29 18:35:25.7899|100|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Found the endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for address Microsoft.AspNetCore.Routing.RouteValuesAddress <br>2024-05-29 18:35:25.7899|102|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Successfully processed template &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; resulting in /Home/Privacy and  <br>2024-05-29 18:35:25.7899|105|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Link generation succeeded for endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; with result /Home/Privacy <br>2024-05-29 18:35:25.7899|100|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Found the endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for address Microsoft.AspNetCore.Routing.RouteValuesAddress <br>2024-05-29 18:35:25.7899|102|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Successfully processed template &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; for Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; resulting in /Home/Privacy and  <br>2024-05-29 18:35:25.7899|105|DEBUG|Microsoft.AspNetCore.Routing.DefaultLinkGenerator|Link generation succeeded for endpoints Route: &#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125; with result /Home/Privacy <br>2024-05-29 18:35:25.9178|4|INFO|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|Executed ViewResult - view Index executed in 231.1047ms. <br>2024-05-29 18:35:25.9178|5|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|After executing action result Microsoft.AspNetCore.Mvc.ViewResult. <br>2024-05-29 18:35:25.9178|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Result Filter: Before executing OnResultExecuted on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.9178|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Result Filter: After executing OnResultExecuted on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.9178|2|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Resource Filter: Before executing OnResourceExecuted on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.9178|3|TRACE|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Resource Filter: After executing OnResourceExecuted on filter Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.SaveTempDataFilter. <br>2024-05-29 18:35:25.9178|2|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executed action ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example) in 261.5085ms <br>2024-05-29 18:35:25.9178|1|INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executed endpoint &#x27;ASP.NetCore6_NLog_Web_Example.Controllers.HomeController.Index (ASP.NetCore6_NLog_Web_Example)&#x27; <br>2024-05-29 18:35:25.9417|1|DEBUG|Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware|Response markup is scheduled to include browser refresh script injection. <br>2024-05-29 18:35:25.9571|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 1 with length 67 and flags END_HEADERS. <br>2024-05-29 18:35:25.9571|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 1 with length 1024 and flags NONE. <br>2024-05-29 18:35:25.9571|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 1 with length 1024 and flags NONE. <br>2024-05-29 18:35:25.9571|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 1 with length 917 and flags NONE. <br>2024-05-29 18:35:25.9571|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 1 with length 65 and flags NONE. <br>2024-05-29 18:35:25.9571|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 1 with length 18 and flags NONE. <br>2024-05-29 18:35:25.9749|2|DEBUG|Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware|Response markup was updated to include browser refresh script injection. <br>2024-05-29 18:35:25.9834|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 1 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:25.9962|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/ - - - 200 - text/html;+charset=utf-8 456.1640ms <br>2024-05-29 18:35:26.0191|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 3 with length 106 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 5 with length 67 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 7 with length 91 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/css/site.css?v=AKvNjO3dCPPS0eSU1Ez8T2wI280i08yGycV9ndytL-c - - <br>2024-05-29 18:35:26.0257|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/lib/bootstrap/dist/css/bootstrap.min.css - - <br>2024-05-29 18:35:26.0257|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:26.0257|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 9 with length 55 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 11 with length 55 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 13 with length 67 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 15 with length 52 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|37|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; received HEADERS frame for stream ID 17 with length 34 and flags END_STREAM, END_HEADERS, PRIORITY. <br>2024-05-29 18:35:26.0257|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/ASP.NetCore6_NLog_Web_Example.styles.css?v=RE8iCRyLdOMjrQXlLNeo4W3xw0k_zNKqvYCiPxC_9nE - - <br>2024-05-29 18:35:26.0257|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:26.0416|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/lib/jquery/dist/jquery.min.js - - <br>2024-05-29 18:35:26.0416|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:26.0416|0|TRACE|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Range header&#x27;s value is empty. <br>2024-05-29 18:35:26.0416|0|TRACE|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Range header&#x27;s value is empty. <br>2024-05-29 18:35:26.0416|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/lib/bootstrap/dist/js/bootstrap.bundle.min.js - - <br>2024-05-29 18:35:26.0416|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:26.0416|0|TRACE|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Range header&#x27;s value is empty. <br>2024-05-29 18:35:26.0416|0|TRACE|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Range header&#x27;s value is empty. <br>2024-05-29 18:35:26.0416|0|TRACE|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Range header&#x27;s value is empty. <br>2024-05-29 18:35:26.0416|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 7 with length 77 and flags END_HEADERS. <br>2024-05-29 18:35:26.0416|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 7 with length 1146 and flags NONE. <br>2024-05-29 18:35:26.0416|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 9 with length 86 and flags END_HEADERS. <br>2024-05-29 18:35:26.0416|2|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Sending file. Request path: &#x27;/ASP.NetCore6_NLog_Web_Example.styles.css&#x27;. Physical path: &#x27;C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\obj\Debug\net6.0\scopedcss\bundle\ASP.NetCore6_NLog_Web_Example.styles.css&#x27; <br>2024-05-29 18:35:26.0416|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 7 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.0416|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/ASP.NetCore6_NLog_Web_Example.styles.css?v=RE8iCRyLdOMjrQXlLNeo4W3xw0k_zNKqvYCiPxC_9nE - - - 200 1146 text/css 15.8363ms <br>2024-05-29 18:35:26.0416|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0 - - <br>2024-05-29 18:35:26.0416|2|TRACE|Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware|All hosts are allowed. <br>2024-05-29 18:35:26.0416|0|TRACE|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Range header&#x27;s value is empty. <br>2024-05-29 18:35:26.0416|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 11 with length 33 and flags END_HEADERS. <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 11 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 3 with length 34 and flags END_HEADERS. <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.0553|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/_framework/aspnetcore-browser-refresh.js - - <br>2024-05-29 18:35:26.0553|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7125/_vs/browserLink - - <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 5 with length 31 and flags END_HEADERS. <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 13 with length 31 and flags END_HEADERS. <br>2024-05-29 18:35:26.0553|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 11 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.0924|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 5 with length 194 and flags NONE. <br>2024-05-29 18:35:26.0924|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.0924|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 13 with length 230 and flags NONE. <br>2024-05-29 18:35:26.0924|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 15 with length 60 and flags END_HEADERS. <br>2024-05-29 18:35:26.0924|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 15 with length 12024 and flags NONE. <br>2024-05-29 18:35:26.0924|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending HEADERS frame for stream ID 17 with length 119 and flags END_HEADERS. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 9986 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1097|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 15 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 11 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/_framework/aspnetcore-browser-refresh.js - - - 200 12024 application/javascript;+charset=utf-8 55.1341ms <br>2024-05-29 18:35:26.1195|2|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Sending file. Request path: &#x27;/css/site.css&#x27;. Physical path: &#x27;C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\wwwroot\css\site.css&#x27; <br>2024-05-29 18:35:26.1195|2|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Sending file. Request path: &#x27;/js/site.js&#x27;. Physical path: &#x27;C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\wwwroot\js\site.js&#x27; <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 5 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1195|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/css/site.css?v=AKvNjO3dCPPS0eSU1Ez8T2wI280i08yGycV9ndytL-c - - - 200 194 text/css 94.5017ms <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 11 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 13 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1195|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0 - - - 200 230 application/javascript 77.4123ms <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1195|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 11 with length 12938 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 7558 and flags NONE. <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Sending file. Request path: &#x27;/lib/jquery/dist/jquery.min.js&#x27;. Physical path: &#x27;C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\wwwroot\lib\jquery\dist\jquery.min.js&#x27; <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 9 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Sending file. Request path: &#x27;/lib/bootstrap/dist/js/bootstrap.bundle.min.js&#x27;. Physical path: &#x27;C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.min.js&#x27; <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/lib/jquery/dist/jquery.min.js - - - 200 89478 application/javascript 93.8938ms <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 11 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/lib/bootstrap/dist/js/bootstrap.bundle.min.js - - - 200 78474 application/javascript 93.0748ms <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 10240 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 9975 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 16384 and flags NONE. <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 15270 and flags NONE. <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|Sending file. Request path: &#x27;/lib/bootstrap/dist/css/bootstrap.min.css&#x27;. Physical path: &#x27;C:\Users\XXX\source\repos\NLog.Web\examples\ASP.NET Core 6\ASP.NET Core 6 NLog Example\wwwroot\lib\bootstrap\dist\css\bootstrap.min.css&#x27; <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 3 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/lib/bootstrap/dist/css/bootstrap.min.css - - - 200 162726 text/css 109.3089ms <br>2024-05-29 18:35:26.1329|49|TRACE|Microsoft.AspNetCore.Server.Kestrel.Http2|Connection id &quot;0HMK16UJ982TT&quot; sending DATA frame for stream ID 17 with length 0 and flags END_STREAM. <br>2024-05-29 18:35:26.1329|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7125/_vs/browserLink - - - 200 - text/javascript;+charset=UTF-8 71.3116ms <br></code></pre></td></tr></table></figure><h2 id="六、模型绑定"><a href="#六、模型绑定" class="headerlink" title="六、模型绑定"></a>六、模型绑定</h2><p>下面是对应的 URL 示例：</p><h3 id="1-路由参数"><a href="#1-路由参数" class="headerlink" title="1. 路由参数"></a>1. 路由参数</h3><h4 id="接收单个参数"><a href="#接收单个参数" class="headerlink" title="接收单个参数"></a>接收单个参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpGet(<span class="hljs-string">&quot;api/products/&#123;id&#125;&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetProductById</span>(<span class="hljs-params">[FromRoute] <span class="hljs-built_in">int</span> id</span>)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的 URL 示例：<code>/api/products/123</code></p><h3 id="2-URL-参数"><a href="#2-URL-参数" class="headerlink" title="2. URL 参数"></a>2. URL 参数</h3><h4 id="接收单个参数-1"><a href="#接收单个参数-1" class="headerlink" title="接收单个参数"></a>接收单个参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpGet(<span class="hljs-string">&quot;api/products&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetProducts</span>(<span class="hljs-params">[FromQuery] <span class="hljs-built_in">int</span> page</span>)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的 URL 示例：<code>/api/products?page=1</code></p><h4 id="接收数组参数"><a href="#接收数组参数" class="headerlink" title="接收数组参数"></a>接收数组参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpGet(<span class="hljs-string">&quot;api/products&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetProducts</span>(<span class="hljs-params">[FromQuery(Name = <span class="hljs-string">&quot;ids[]&quot;</span></span>)] <span class="hljs-built_in">int</span>[] ids)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的 URL 示例：<code>/api/products?ids[]=1&amp;ids[]=2&amp;ids[]=3</code></p><h4 id="接收对象参数"><a href="#接收对象参数" class="headerlink" title="接收对象参数"></a>接收对象参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpGet(<span class="hljs-string">&quot;api/products&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetProducts</span>(<span class="hljs-params">[FromQuery] Product product</span>)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的 URL 示例：<code>/api/products?Name=ProductName&amp;Price=99.99</code></p><h3 id="3-请求体参数"><a href="#3-请求体参数" class="headerlink" title="3. 请求体参数"></a>3. 请求体参数</h3><h4 id="接收单个参数-2"><a href="#接收单个参数-2" class="headerlink" title="接收单个参数"></a>接收单个参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpPost(<span class="hljs-string">&quot;api/products&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">CreateProduct</span>(<span class="hljs-params">[FromBody] <span class="hljs-built_in">string</span> productName</span>)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的请求体示例：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;productName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Product Name&quot;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h4 id="接收数组参数-1"><a href="#接收数组参数-1" class="headerlink" title="接收数组参数"></a>接收数组参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpPost(<span class="hljs-string">&quot;api/products&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">CreateProducts</span>(<span class="hljs-params">[FromBody] List&lt;<span class="hljs-built_in">string</span>&gt; productNames</span>)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的请求体示例：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">[</span><span class="hljs-string">&quot;Product 1&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-string">&quot;Product 2&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-string">&quot;Product 3&quot;</span><span class="hljs-punctuation">]</span><br></code></pre></td></tr></table></figure><h4 id="接收对象参数-1"><a href="#接收对象参数-1" class="headerlink" title="接收对象参数"></a>接收对象参数</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">[<span class="hljs-meta">HttpPost(<span class="hljs-string">&quot;api/products&quot;</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">CreateProduct</span>(<span class="hljs-params">[FromBody] Product product</span>)</span><br>&#123;<br>    <span class="hljs-keyword">return</span> Ok();<br>&#125;<br></code></pre></td></tr></table></figure><p>对应的请求体示例：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;id&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">123</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Product Name&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;price&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">99.99</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><p>这些示例展示了在 ASP.NET Core Web API 中如何从路由、URL 和请求体中接收参数，并进行相应的参数绑定。</p><h2 id="七、模型验证"><a href="#七、模型验证" class="headerlink" title="七、模型验证"></a>七、模型验证</h2><p>在 Web API 中，模型验证是确保客户端提供的数据符合预期的关键部分之一。这不仅有助于保护应用程序免受恶意输入的影响，还可以提高应用程序的健壮性和可靠性。</p><h3 id="1-内置验证特性"><a href="#1-内置验证特性" class="headerlink" title="1. 内置验证特性"></a>1. 内置验证特性</h3><p>ASP.NET Core 提供了一系列内置的验证特性，可以直接应用于模型的属性上。通过在模型的属性上应用这些特性，我们可以定义属性的验证规则和错误消息，以确保接收到的数据是有效的和完整的。</p><p>示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System.ComponentModel.DataAnnotations;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserModel</span><br>&#123;<br>    [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-string">&quot;用户名不能为空&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Username &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-string">&quot;密码不能为空&quot;</span>)</span>]<br>    [<span class="hljs-meta">StringLength(20, MinimumLength = 6, ErrorMessage = <span class="hljs-string">&quot;密码长度必须在6到20个字符之间&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Password &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">EmailAddress(ErrorMessage = <span class="hljs-string">&quot;无效的邮箱地址&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Email &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">Range(18, 100, ErrorMessage = <span class="hljs-string">&quot;年龄必须在18到100岁之间&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> Age &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">Phone(ErrorMessage = <span class="hljs-string">&quot;无效的电话号码&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> PhoneNumber &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">RegularExpression(@<span class="hljs-string">&quot;^[A-Za-z0-9]+(?:[_-][A-Za-z0-9]+)*$&quot;</span>, ErrorMessage = <span class="hljs-string">&quot;用户名只能包含字母、数字、下划线和短横线&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Username &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">Compare(<span class="hljs-string">&quot;Password&quot;</span>, ErrorMessage = <span class="hljs-string">&quot;确认密码与密码不匹配&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> ConfirmPassword &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">Url(ErrorMessage = <span class="hljs-string">&quot;无效的 URL 地址&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Website &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">CreditCard(ErrorMessage = <span class="hljs-string">&quot;无效的信用卡号&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> CreditCardNumber &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>    [<span class="hljs-meta">DataType(DataType.Date, ErrorMessage = <span class="hljs-string">&quot;请输入有效的日期&quot;</span>)</span>]<br>    <span class="hljs-keyword">public</span> DateTime BirthDate &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h3 id="2-手动验证获取参数绑定失败的消息"><a href="#2-手动验证获取参数绑定失败的消息" class="headerlink" title="2. 手动验证获取参数绑定失败的消息"></a>2. 手动验证获取参数绑定失败的消息</h3><p>有时候，我们需要手动获取参数绑定失败的消息。为了实现这一点，我们可以创建一个静态的 AspNetCoreHelper 类，其中包含一个 ValidateModelStateForApi 方法，用于验证模型的状态并获取绑定失败的消息。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AspNetCoreHelper</span><br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ValidateModelStateForApi</span>(<span class="hljs-params">ModelStateDictionary modelState</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">if</span> (!modelState.IsValid)<br>        &#123;<br>            <span class="hljs-keyword">var</span> errorMessages = <span class="hljs-built_in">string</span>.Join(Environment.NewLine,<br>                modelState.Values.SelectMany(v =&gt; v.Errors.Select(e =&gt; !<span class="hljs-built_in">string</span>.IsNullOrEmpty(e.ErrorMessage) ? e.ErrorMessage : e.Exception?.Message)));<br><br>            <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">string</span>.IsNullOrEmpty(errorMessages))<br>            &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(errorMessages);<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-进阶使用-FluentValidation-自定义规则更灵活的验证参数"><a href="#3-进阶使用-FluentValidation-自定义规则更灵活的验证参数" class="headerlink" title="3. 进阶使用 FluentValidation 自定义规则更灵活的验证参数"></a>3. 进阶使用 FluentValidation 自定义规则更灵活的验证参数</h3><p>FluentValidation 是一个强大且灵活的验证库，可以用于定义复杂的验证规则。以下是使用 FluentValidation 进行模型验证的简单教程：</p><h3 id="3-1-安装-FluentValidation-包"><a href="#3-1-安装-FluentValidation-包" class="headerlink" title="3.1. 安装 FluentValidation 包"></a>3.1. 安装 FluentValidation 包</h3><p>首先，使用 NuGet 包管理器或 .NET CLI 安装 FluentValidation 包。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet add package FluentValidation<br></code></pre></td></tr></table></figure><h3 id="3-2-创建验证器类"><a href="#3-2-创建验证器类" class="headerlink" title="3.2. 创建验证器类"></a>3.2. 创建验证器类</h3><p>创建一个验证器类，用于定义模型验证规则。例如，如果我们有一个名为 <code>Product</code> 的模型类，可以创建一个 <code>ProductValidator</code> 的验证器类来定义验证规则。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> FluentValidation;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ProductValidator</span> : <span class="hljs-title">AbstractValidator</span>&lt;<span class="hljs-title">Product</span>&gt;<br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProductValidator</span>()</span><br>    &#123;<br>        RuleFor(product =&gt; product.Name).NotEmpty().WithMessage(<span class="hljs-string">&quot;Name is required.&quot;</span>);<br>        RuleFor(product =&gt; product.Price).GreaterThan(<span class="hljs-number">0</span>).WithMessage(<span class="hljs-string">&quot;Price must be greater than 0.&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-3-在控制器中使用验证器"><a href="#3-3-在控制器中使用验证器" class="headerlink" title="3.3. 在控制器中使用验证器"></a>3.3. 在控制器中使用验证器</h3><p>在控制器中使用验证器类来执行模型验证。在控制器的相应动作方法中，实例化验证器并对模型对象进行验证。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;<br><br>[<span class="hljs-meta">ApiController</span>]<br>[<span class="hljs-meta">Route(<span class="hljs-string">&quot;api/[controller]&quot;</span>)</span>]<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ProductsController</span> : <span class="hljs-title">ControllerBase</span><br>&#123;<br>    [<span class="hljs-meta">HttpPost</span>]<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">CreateProduct</span>(<span class="hljs-params">[FromBody] Product product</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">var</span> validator = <span class="hljs-keyword">new</span> ProductValidator();<br>        <span class="hljs-keyword">var</span> validationResult = validator.Validate(product);<br><br>        <span class="hljs-keyword">if</span> (!validationResult.IsValid)<br>        &#123;<br>            <span class="hljs-keyword">var</span> errors = validationResult.Errors.Select(error =&gt; error.ErrorMessage);<br>            <span class="hljs-keyword">return</span> BadRequest(errors);<br>        &#125;<br><br>        <span class="hljs-comment">// 执行创建产品的逻辑</span><br>        <span class="hljs-keyword">return</span> Ok(<span class="hljs-string">&quot;Product created successfully!&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-4-测试模型验证"><a href="#3-4-测试模型验证" class="headerlink" title="3.4. 测试模型验证"></a>3.4. 测试模型验证</h3><p>通过发送 POST 请求来测试模型验证。可以使用 Postman 或其他 HTTP 客户端来发送请求。</p><ul><li>URL：<code>POST /api/products</code></li><li>请求体：JSON 格式的产品数据</li></ul><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Product Name&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;price&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">99.99</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h2 id="八、使用-Swagger-构建-Web-API-文档"><a href="#八、使用-Swagger-构建-Web-API-文档" class="headerlink" title="八、使用 Swagger 构建 Web API 文档"></a>八、使用 Swagger 构建 Web API 文档</h2><p>Swagger 是一个流行的 Web API 文档工具，可以帮助开发人员设计、构建、记录和使用 API。在 ASP.NET Core 中，使用 Swagger 可以轻松地生成易懂的 Web API 文档，并解决一些常见的问题。下面是一份通俗易懂的使用 Swagger 的指南，同时也提供了一些常见问题的解决方案。</p><h3 id="1-安装-Swagger"><a href="#1-安装-Swagger" class="headerlink" title="1. 安装 Swagger"></a>1. 安装 Swagger</h3><p>首先，我们需要在 ASP.NET Core 项目中安装 Swagger 相关的 NuGet 包。</p><ol><li>打开 NuGet 包管理器控制台。</li><li>运行以下命令来安装 Swashbuckle.AspNetCore：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">Install-Package Swashbuckle.AspNetCore<br></code></pre></td></tr></table></figure><h3 id="2-配置-Swagger"><a href="#2-配置-Swagger" class="headerlink" title="2. 配置 Swagger"></a>2. 配置 Swagger</h3><p>在项目的 <code>Startup.cs</code> 文件中配置 Swagger 服务。</p><ol><li>在 <code>ConfigureServices</code> 方法中，添加 Swagger 服务的配置：</li></ol><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp">services.AddSwaggerGen(c =&gt;<br>&#123;<br>    c.SwaggerDoc(<span class="hljs-string">&quot;v1&quot;</span>, <span class="hljs-keyword">new</span> Microsoft.OpenApi.Models.OpenApiInfo &#123; Title = <span class="hljs-string">&quot;Your API Name&quot;</span>, Version = <span class="hljs-string">&quot;v1&quot;</span> &#125;);<br>&#125;);<br></code></pre></td></tr></table></figure><ol start="2"><li>在 <code>Configure</code> 方法中启用 Swagger 中间件：</li></ol><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">app.UseSwagger();<br>app.UseSwaggerUI(c =&gt;<br>&#123;<br>    c.SwaggerEndpoint(<span class="hljs-string">&quot;/swagger/v1/swagger.json&quot;</span>, <span class="hljs-string">&quot;Your API V1&quot;</span>);<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="3-添加中文注释"><a href="#3-添加中文注释" class="headerlink" title="3. 添加中文注释"></a>3. 添加中文注释</h3><p>如果你希望在 Swagger 文档中显示中文注释，可以进行如下配置。</p><ol><li>在项目的属性中，启用 XML 文档生成。</li><li>在 <code>ConfigureServices</code> 方法中，添加 XML 文档的注释路径：</li></ol><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp">services.AddSwaggerGen(c =&gt;<br>&#123;<br>    <span class="hljs-keyword">var</span> xmlFilename = <span class="hljs-string">$&quot;<span class="hljs-subst">&#123;Assembly.GetExecutingAssembly().GetName().Name&#125;</span>.xml&quot;</span>;<br>    c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename), <span class="hljs-literal">true</span>);<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="5-添加身份验证令牌"><a href="#5-添加身份验证令牌" class="headerlink" title="5. 添加身份验证令牌"></a>5. 添加身份验证令牌</h3><p>在 <code>ConfigureServices</code> 方法中配置 Swagger。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs csharp">services.AddSwaggerGen(c =&gt;<br>&#123;<br>    <span class="hljs-comment">// 配置 Swagger 文档的安全定义</span><br>    c.AddSecurityDefinition(<span class="hljs-string">&quot;Bearer&quot;</span>, <span class="hljs-keyword">new</span> OpenApiSecurityScheme<br>    &#123;<br>        Description = <span class="hljs-string">&quot;JWT授权token前面需要加上字段Bearer与一个空格,如Bearer token&quot;</span>,<br>        Name = <span class="hljs-string">&quot;Authorization&quot;</span>,<br>        In = ParameterLocation.Header,<br>        Type = SecuritySchemeType.ApiKey,<br>        Scheme = <span class="hljs-string">&quot;Bearer&quot;</span><br>    &#125;);<br><br>    <span class="hljs-comment">// 添加 Swagger 文档的全局安全要求</span><br>    c.AddSecurityRequirement(<span class="hljs-keyword">new</span> OpenApiSecurityRequirement<br>    &#123;<br>        &#123;<br>            <span class="hljs-keyword">new</span> OpenApiSecurityScheme<br>            &#123;<br>                Reference = <span class="hljs-keyword">new</span> OpenApiReference &#123; Type = ReferenceType.SecurityScheme, Id = <span class="hljs-string">&quot;Bearer&quot;</span> &#125;<br>            &#125;,<br>            <span class="hljs-keyword">new</span> <span class="hljs-built_in">string</span>[] &#123;&#125;<br>        &#125;<br>    &#125;);<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="4-解决常见问题"><a href="#4-解决常见问题" class="headerlink" title="4. 解决常见问题"></a>4. 解决常见问题</h3><h4 id="4-1-使用相同类名的-Schema-会导致报错"><a href="#4-1-使用相同类名的-Schema-会导致报错" class="headerlink" title="4.1. 使用相同类名的 Schema 会导致报错"></a>4.1. 使用相同类名的 Schema 会导致报错</h4><p>如果在项目中存在相同类名的情况，可以通过配置避免这个问题。</p><p>在 <code>ConfigureServices</code> 方法中，添加如下配置：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp">services.AddSwaggerGen(c =&gt;<br>&#123;<br>    c.CustomSchemaIds(type =&gt; SwaggerHelper.GetSchemaId(type));<br>&#125;)<br></code></pre></td></tr></table></figure><p>自定义 <strong>SchemaId</strong>   如下：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SwaggerHelper</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> ConcurrentDictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">int</span>&gt; _schemaNameRepetition = <span class="hljs-keyword">new</span>();<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> <span class="hljs-title">DefaultSchemaIdSelector</span>(<span class="hljs-params">Type modelType</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">if</span> (!modelType.IsConstructedGenericType) <span class="hljs-keyword">return</span> modelType.Name.Replace(<span class="hljs-string">&quot;[]&quot;</span>, <span class="hljs-string">&quot;Array&quot;</span>);<br><br>        <span class="hljs-keyword">var</span> prefixBuilder = <span class="hljs-keyword">new</span> StringBuilder();<br>        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> genericArg <span class="hljs-keyword">in</span> modelType.GetGenericArguments())<br>        &#123;<br>            prefixBuilder.Append(DefaultSchemaIdSelector(genericArg));<br>        &#125;<br><br>        <span class="hljs-keyword">var</span> prefix = prefixBuilder.ToString();<br>        <span class="hljs-keyword">return</span> prefix + modelType.Name.Split(<span class="hljs-string">&#x27;`&#x27;</span>).First();<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GetSchemaId</span>(<span class="hljs-params">Type modelType</span>)</span><br>    &#123;<br>        <span class="hljs-built_in">string</span> id;<br>        id = DefaultSchemaIdSelector(modelType);<br>        _schemaNameRepetition.AddOrUpdate(id, <span class="hljs-number">1</span>, (_, count) =&gt; count + <span class="hljs-number">1</span>);<br><br>        <span class="hljs-built_in">int</span> count = _schemaNameRepetition[id];<br><br><br>        <span class="hljs-keyword">return</span> <span class="hljs-string">$&quot;<span class="hljs-subst">&#123;id&#125;</span><span class="hljs-subst">&#123;(count &gt; <span class="hljs-number">1</span> ? count.ToString() : <span class="hljs-string">&quot;&quot;</span>)&#125;</span>&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="4-2-接口返回数据字段变成小写"><a href="#4-2-接口返回数据字段变成小写" class="headerlink" title="4.2. 接口返回数据字段变成小写"></a>4.2. 接口返回数据字段变成小写</h4><p>有时接口返回的数据字段会变成小写，可以通过配置解决。</p><p>在 <code>Startup.cs</code> 文件的 <code>ConfigureServices</code> 方法中，添加如下配置：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs csharp">services.AddControllers()<br>    .AddNewtonsoftJson(op =&gt;<br>    &#123;<br>        <span class="hljs-comment">// 解决接口返回的字段变成小写问题，还原模型原本的字段名</span><br>        op.SerializerSettings.ContractResolver = <span class="hljs-keyword">new</span> Newtonsoft.Json.Serialization.DefaultContractResolver();<br>    &#125;);<br></code></pre></td></tr></table></figure><h4 id="4-2-超过-1MB-的-JSON-响应数据导致-Swagger-一直加载"><a href="#4-2-超过-1MB-的-JSON-响应数据导致-Swagger-一直加载" class="headerlink" title="4.2. 超过 1MB 的 JSON 响应数据导致 Swagger 一直加载"></a>4.2. 超过 1MB 的 JSON 响应数据导致 Swagger 一直加载</h4><p>在 <code>Startup.cs</code> 文件的 <code>Configure</code> 方法中，添加如下配置：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp">app.UseSwaggerUI(c =&gt;<br>&#123;<br>    c.ConfigObject.AdditionalItems[<span class="hljs-string">&quot;syntaxHighlight&quot;</span>] = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">object</span>&gt;<br>    &#123;<br>        [<span class="hljs-string">&quot;activated&quot;</span>] = <span class="hljs-literal">false</span><br>    &#125;;<br>&#125;);<br></code></pre></td></tr></table></figure><h2 id="九、使用-EF-Core-操作数据库"><a href="#九、使用-EF-Core-操作数据库" class="headerlink" title="九、使用 EF Core 操作数据库"></a>九、使用 EF Core 操作数据库</h2><p>当使用 CLI 工具初始化模型并从配置文件中读取数据库连接字符串时，可以按照以下步骤进行操作：</p><h3 id="1-安装-Entity-Framework-Core-CLI-工具"><a href="#1-安装-Entity-Framework-Core-CLI-工具" class="headerlink" title="1. 安装 Entity Framework Core CLI 工具"></a>1. 安装 Entity Framework Core CLI 工具</h3><p>首先，确保已经安装了 Entity Framework Core 工具。你可以通过以下命令来全局安装 EF Core 工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet tool install --global dotnet-ef<br></code></pre></td></tr></table></figure><p>这将安装 EF Core 工具，使你可以在命令行或终端中使用 <code>dotnet ef</code> 命令。</p><h3 id="2-安装-EF-Core-包"><a href="#2-安装-EF-Core-包" class="headerlink" title="2. 安装 EF Core 包"></a>2. 安装 EF Core 包</h3><p>在项目目录中安装 Entity Framework Core 包。可以使用 NuGet 包管理器或 .NET CLI 来安装。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet add package Microsoft.EntityFrameworkCore<br>dotnet add package Microsoft.EntityFrameworkCore.SqlServer<br>dotnet add package Microsoft.EntityFrameworkCore.Tools<br></code></pre></td></tr></table></figure><h3 id="3-使用-CLI-工具初始化模型"><a href="#3-使用-CLI-工具初始化模型" class="headerlink" title="3. 使用 CLI 工具初始化模型"></a>3. 使用 CLI 工具初始化模型</h3><h4 id="常用选项"><a href="#常用选项" class="headerlink" title="常用选项"></a>常用选项</h4><table><thead><tr><th align="left">选项</th><th align="left">Short</th><th align="left">说明</th></tr></thead><tbody><tr><td align="left"><code>--json</code></td><td align="left"></td><td align="left">显示 JSON 输出。</td></tr><tr><td align="left"><code>--context </code></td><td align="left"><code>-c</code></td><td align="left">要使用的 <code>DbContext</code> 类。 仅类名或完全限定命名的空间。 如果省略此选项，EF Core 将查找上下文类。 如果有多个上下文类，则此选项是必需的。</td></tr><tr><td align="left"><code>--project </code></td><td align="left"><code>-p</code></td><td align="left">目标项目的项目文件夹的相对路径。 默认值是当前文件夹。</td></tr><tr><td align="left"><code>--startup-project </code></td><td align="left"><code>-s</code></td><td align="left">启动项目的项目文件夹的相对路径。 默认值是当前文件夹。</td></tr><tr><td align="left"><code>--framework </code></td><td align="left"></td><td align="left"><a href="https://learn.microsoft.com/zh-cn/dotnet/standard/frameworks">目标框架</a>的<a href="https://learn.microsoft.com/zh-cn/dotnet/standard/frameworks#supported-target-framework-versions">目标框架名字对象</a>。 当项目文件指定了多个目标框架，并且你想要选择其中一个目标框架时，请使用此选项。</td></tr><tr><td align="left"><code>--configuration </code></td><td align="left"></td><td align="left">生成配置，例如 <code>Debug</code> 或 <code>Release</code>。</td></tr><tr><td align="left"><code>--runtime </code></td><td align="left"></td><td align="left">要为其还原包的目标运行时的标识符。 有关运行时标识符 (RID) 的列表，请参阅 <a href="https://learn.microsoft.com/zh-cn/dotnet/core/rid-catalog">RID 目录</a>。</td></tr><tr><td align="left"><code>--no-build</code></td><td align="left"></td><td align="left">请勿生成项目。 旨在在生成处于最新状态时使用。</td></tr><tr><td align="left"><code>--help</code></td><td align="left"><code>-h</code></td><td align="left">显示帮助信息。</td></tr><tr><td align="left"><code>--verbose</code></td><td align="left"><code>-v</code></td><td align="left">显示详细输出。</td></tr><tr><td align="left"><code>--no-color</code></td><td align="left"></td><td align="left">请勿为输出着色。</td></tr><tr><td align="left"><code>--prefix-output</code></td><td align="left"></td><td align="left">具有级别的前缀输出。</td></tr></tbody></table><p>首先，在项目的根目录下打开命令行或终端窗口，并使用 EF Core CLI 工具来初始化模型类。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet ef dbcontext scaffold <span class="hljs-string">&quot;connection_string_here&quot;</span> Microsoft.EntityFrameworkCore.SqlServer -o Models -c ApplicationDbContext --data-annotations -f --no-pluralize<br></code></pre></td></tr></table></figure><p>替换 <code>&quot;connection_string_here&quot;</code> 为你的数据库连接字符串，<code>-o Models</code> 参数指定了模型类文件的输出目录。这个命令会根据数据库的结构自动生成模型类文件。</p><h4 id="dotnet-ef-dbcontext-scaffold"><a href="#dotnet-ef-dbcontext-scaffold" class="headerlink" title="dotnet ef dbcontext scaffold"></a><code>dotnet ef dbcontext scaffold</code></h4><p>为 <code>DbContext</code> 生成代码，并为数据库生成实体类型。 为了让此命令生成实体类型，数据库表必须具有主键。</p><p>参数：</p><table><thead><tr><th align="left">参数</th><th align="left">说明</th></tr></thead><tbody><tr><td align="left"><code>&lt;CONNECTION&gt;</code></td><td align="left">用于连接到数据库的连接字符串。 对于 ASP.NET Core 2.x 项目，值可以是 name&#x3D;<name of connection string>。 在这种情况下，名称来自为项目设置的配置源。</td></tr><tr><td align="left"><code>&lt;PROVIDER&gt;</code></td><td align="left">要使用的提供程序。 通常，这是 NuGet 包的名称，例如：<code>Microsoft.EntityFrameworkCore.SqlServer</code>。</td></tr></tbody></table><p>选项：</p><table><thead><tr><th align="left">选项</th><th align="left">Short</th><th align="left">说明</th></tr></thead><tbody><tr><td align="left"><code>--data-annotations</code></td><td align="left"><code>-d</code></td><td align="left">使用属性配置模型（如果可能）。 如果省略此选项，则仅使用 Fluent API。</td></tr><tr><td align="left"><code>--context </code></td><td align="left"><code>-c</code></td><td align="left">要生成的 <code>DbContext</code> 类的名称。</td></tr><tr><td align="left"><code>--context-dir </code></td><td align="left"></td><td align="left">要在其中放置 <code>DbContext</code> 类文件的目录。 路径相对于项目目录。 命名空间派生自文件夹名称。</td></tr><tr><td align="left"><code>--context-namespace </code></td><td align="left"></td><td align="left">要用于生成的 <code>DbContext</code> 类的命名空间。 注意：重写 <code>--namespace</code>。</td></tr><tr><td align="left"><code>--force</code></td><td align="left"><code>-f</code></td><td align="left">覆盖现有文件。</td></tr><tr><td align="left"><code>--output-dir </code></td><td align="left"><code>-o</code></td><td align="left">要在其中放置实体类文件的目录。 路径相对于项目目录。</td></tr><tr><td align="left"><code>--namespace </code></td><td align="left"><code>-n</code></td><td align="left">要用于所有生成的类的命名空间。 默认设置为从根命名空间和输出目录生成。</td></tr><tr><td align="left"><code>--schema ...</code></td><td align="left"></td><td align="left">要为其生成实体类型的表和视图的架构。 若要指定多个架构，请为每个架构重复 <code>--schema</code>。 如果省略此选项，则包含所有架构。 如果使用此选项，架构中的所有表和视图都将包含在模型中，即使未使用 –table 显式包含它们也是如此。</td></tr><tr><td align="left"><code>--table ...</code></td><td align="left"><code>-t</code></td><td align="left">要为其生成实体类型的表和视图。 若要指定多个表，请为每个表重复 <code>-t</code> 或 <code>--table</code>。 可以使用“schema.table”或“schema.view”格式包含特定架构中的表或视图。 如果省略此选项，则包含所有表和视图。</td></tr><tr><td align="left"><code>--use-database-names</code></td><td align="left"></td><td align="left">使用与数据库中显示的名称完全相同的表、视图、序列和列名称。 如果省略此选项，数据库名称将更改为更符合 C# 名称样式约定。</td></tr><tr><td align="left"><code>--no-onconfiguring</code></td><td align="left"></td><td align="left">禁止在生成的 <code>DbContext</code> 类中生成 <code>OnConfiguring</code> 方法。</td></tr><tr><td align="left"><code>--no-pluralize</code></td><td align="left"></td><td align="left">请勿使用复数化程序。</td></tr></tbody></table><h3 id="4-配置数据库连接字符串"><a href="#4-配置数据库连接字符串" class="headerlink" title="4. 配置数据库连接字符串"></a>4. 配置数据库连接字符串</h3><p>在 <code>appsettings.json</code> 文件中配置数据库连接字符串。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>  <span class="hljs-attr">&quot;ConnectionStrings&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;DefaultConnection&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;your_connection_string_here&quot;</span><br>  <span class="hljs-punctuation">&#125;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><h3 id="5-配置服务"><a href="#5-配置服务" class="headerlink" title="5. 配置服务"></a>5. 配置服务</h3><p>在 <code>Startup.cs</code> 文件的 <code>ConfigureServices</code> 方法中配置数据库上下文服务。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>&#123;<br>    services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;<br>        options.UseSqlServer(Configuration.GetConnectionString(<span class="hljs-string">&quot;DefaultConnection&quot;</span>)));<br>&#125;<br></code></pre></td></tr></table></figure><p>确保在 <code>Startup.cs</code> 文件的顶部添加了 <code>using</code> 声明：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;<br></code></pre></td></tr></table></figure><h3 id="6-使用数据库上下文"><a href="#6-使用数据库上下文" class="headerlink" title="6. 使用数据库上下文"></a>6. 使用数据库上下文</h3><p>现在，你可以在控制器或其他服务中注入数据库上下文，并使用它来执行数据库操作。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ProductsController</span> : <span class="hljs-title">ControllerBase</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ApplicationDbContext _context;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProductsController</span>(<span class="hljs-params">ApplicationDbContext context</span>)</span><br>    &#123;<br>        _context = context;<br>    &#125;<br><br>    [<span class="hljs-meta">HttpGet</span>]<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetProducts</span>()</span><br>    &#123;<br>        <span class="hljs-keyword">var</span> products = <span class="hljs-keyword">await</span> _context.Products.ToListAsync();<br>        <span class="hljs-keyword">return</span> Ok(products);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="7-调用存储过程与原生SQL"><a href="#7-调用存储过程与原生SQL" class="headerlink" title="7. 调用存储过程与原生SQL"></a>7. 调用存储过程与原生SQL</h3><h4 id="7-1-准备工作"><a href="#7-1-准备工作" class="headerlink" title="7.1. 准备工作"></a>7.1. 准备工作</h4><p>在使用 EF Core 调用存储过程与原生 SQL 之前，需要做以下准备工作：</p><ul><li>在新建的数据库上下文的分部类中添加相应的 DbSet，确保上下文在 CLI 自动生成模型后不会被覆盖。</li></ul><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-comment">// 数据库上下文</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">partial</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyDbContext</span> : <span class="hljs-title">DbContext</span><br>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyDbContext</span>(<span class="hljs-params">DbContextOptions&lt;MyDbContext&gt; options</span>)</span><br><span class="hljs-function">        : <span class="hljs-title">base</span>(<span class="hljs-params">options</span>)</span><br>    &#123;<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 数据库上下文分部类</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">partial</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyDbContext</span><br>&#123;<br>      <span class="hljs-keyword">public</span> DbSet&lt;MyEntity&gt; MyEntities &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h4 id="7-2-代码示例"><a href="#7-2-代码示例" class="headerlink" title="7.2. 代码示例"></a>7.2. 代码示例</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-comment">// 参数值</span><br><span class="hljs-keyword">var</span> param1Value = <span class="hljs-string">&quot;value1&quot;</span>;<br><span class="hljs-keyword">var</span> param2Value = <span class="hljs-string">&quot;value2&quot;</span>;<br><br><span class="hljs-comment">// 直接使用内插字符串</span><br><span class="hljs-keyword">var</span> sqlQuery = <span class="hljs-string">$&quot;EXEC MyStoredProcedure &#x27;<span class="hljs-subst">&#123;param1Value&#125;</span>&#x27;, &#x27;<span class="hljs-subst">&#123;param2Value&#125;</span>&#x27;&quot;</span>;<br><br><span class="hljs-comment">// 使用参数化查询</span><br><span class="hljs-keyword">var</span> sqlQuery1 = <span class="hljs-string">&quot;EXEC MyStoredProcedure @param1, @param2&quot;</span>;<br><span class="hljs-keyword">var</span> sqlQuery2 = <span class="hljs-string">&quot;EXEC MyStoredProcedure &#123;0&#125;, &#123;1&#125;&quot;</span>;<br><br><span class="hljs-comment">// 示例：FromSql（EF Core 7.0 引入和 FromSqlInterpolated 使用一致）</span><br><span class="hljs-keyword">var</span> resultFromSql = dbContext.MyEntity.FromSql(sqlQuery).ToList();<br><br><span class="hljs-comment">// 示例：FromSqlRaw</span><br><span class="hljs-keyword">var</span> resultFromSqlRaw = dbContext.MyEntity.FromSqlRaw(sqlQuery1,<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param1&quot;</span>, param1Value),<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param2&quot;</span>, param2Value)).ToList();<br><br><span class="hljs-keyword">var</span> result1FromSqlRaw = dbContext.MyEntity.FromSqlRaw(sqlQuery2,<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param1&quot;</span>, param1Value),<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param2&quot;</span>, param2Value)).ToList();<br><br><span class="hljs-comment">// 示例：FromSqlInterpolated（自动处理参数化）</span><br><span class="hljs-keyword">var</span> resultFromSqlInterpolated = dbContext.MyEntity.FromSqlInterpolated(sqlQuery).ToList();<br><br><span class="hljs-comment">// 示例：ExecuteSql（EF Core 7.0 引入和 ExecuteSqlInterpolated 使用一致）</span><br><span class="hljs-built_in">int</span> resultExecuteSql = dbContext.Database.ExecuteSql(sqlQuery);<br><br><span class="hljs-comment">// 示例：ExecuteSqlRaw</span><br><span class="hljs-built_in">int</span> resultExecuteSqlRaw = dbContext.Database.ExecuteSqlRaw(sqlQuery1,<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param1&quot;</span>, param1Value),<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param2&quot;</span>, param2Value));<br><br><span class="hljs-built_in">int</span> result1ExecuteSqlRaw = dbContext.Database.ExecuteSqlRaw(sqlQuery2,<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param1&quot;</span>, param1Value),<br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@param2&quot;</span>, param2Value));<br><br><span class="hljs-comment">// 示例：ExecuteSqlInterpolated（自动处理参数化）</span><br><span class="hljs-built_in">int</span> resultExecuteSqlInterpolated = dbContext.Database.ExecuteSqlInterpolated(sqlQuery);<br><br></code></pre></td></tr></table></figure><h4 id="7-3-调用方法和区别"><a href="#7-3-调用方法和区别" class="headerlink" title="7.3. 调用方法和区别"></a>7.3. 调用方法和区别</h4><p>下表列出了各种调用方法的区别：</p><table><thead><tr><th align="left">方法名称</th><th>描述</th><th>参数类型</th><th align="left">备注</th></tr></thead><tbody><tr><td align="left"><strong>FromSql</strong></td><td>创建基于插值字符串表示的 SQL 查询的 LINQ 查询。返回<code>IQueryable&lt;T&gt;</code></td><td><code>FormattableString</code></td><td align="left">使用插值字符串，自动处理参数化</td></tr><tr><td align="left"><strong>FromSqlRaw</strong></td><td>创建基于原始 SQL 查询的 LINQ 查询。返回<code>IQueryable&lt;T&gt;</code></td><td><code>string</code> 和 <code>params object[]</code></td><td align="left">接收原始 SQL 字符串和可选参数。</td></tr><tr><td align="left"><strong>FromSqlInterpolated</strong></td><td>创建基于插值字符串表示的 SQL 查询的 LINQ 查询。返回<code>IQueryable&lt;T&gt;</code></td><td><code>FormattableString</code></td><td align="left">使用插值字符串，自动处理参数化。</td></tr><tr><td align="left"><strong>ExecuteSql</strong></td><td>执行给定的 SQL 并返回受影响的行数。</td><td><code>FormattableString</code></td><td align="left">使用插值字符串，自动处理参数化</td></tr><tr><td align="left"><strong>ExecuteSqlRaw</strong></td><td>执行给定的 SQL 并返回受影响的行数。</td><td><code>string</code> 和 <code>params object[]</code></td><td align="left">接收原始 SQL 字符串和可选参数。</td></tr><tr><td align="left"><strong>ExecuteSqlInterpolated</strong></td><td>执行给定的 SQL 并返回受影响的行数。</td><td><code>FormattableString</code></td><td align="left">使用插值字符串，自动处理参数化。</td></tr></tbody></table><h5 id="详细说明"><a href="#详细说明" class="headerlink" title="详细说明"></a>详细说明</h5><ul><li><strong>FromSql</strong> 和 <strong>FromSqlInterpolated</strong>：EF Core 7.0 引入，两者功能和实现方式一致，都可以自动处理参数化，都用于创建基于插值字符串的 SQL 查询的 LINQ 查询。</li><li><strong>FromSqlRaw</strong>：接收原始 SQL 字符串和参数列表。</li><li><strong>ExecuteSql</strong> 和 <strong>ExecuteSqlInterpolated</strong>：EF Core 7.0 引入，两者功能和实现方式一致，都可以自动处理参数化，都用于执行给定的 SQL 并返回受影响的行数。</li><li><strong>ExecuteSqlRaw</strong>：接收原始 SQL 字符串和参数列表，用于执行给定的 SQL 并返回受影响的行数。</li><li>以上 API 方法，与任何接受 SQL 的 API 一样，重要的是将任何用户输入参数化，以防止 SQL 注入<br>攻击。您可以在 SQL 查询字符串中包含参数占位符，然后提供额外的参数值<br>参数。您提供的任何参数值都将自动转换为 <code>DbParameter</code>。</li></ul><h4 id="7-4-调用带有输出参数的存储过程"><a href="#7-4-调用带有输出参数的存储过程" class="headerlink" title="7.4. 调用带有输出参数的存储过程"></a>7.4. 调用带有输出参数的存储过程</h4><p>要调用带有输出参数的存储过程，可以使用 ExecuteSql 或 ExecuteSqlInterpolated 方法，并通过参数传递输出参数。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> outputParam = <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@outputParam&quot;</span>, SqlDbType.Int)<br>&#123;<br>    Direction = ParameterDirection.Output<br>&#125;;<br><br>dbContext.Database.ExecuteSqlRaw(<span class="hljs-string">&quot;EXEC MyStoredProcedure @inputParam, @outputParam OUTPUT&quot;</span>, <br>    <span class="hljs-keyword">new</span> SqlParameter(<span class="hljs-string">&quot;@inputParam&quot;</span>, param1),<br>    outputParam);<br><br><span class="hljs-built_in">int</span> result = (<span class="hljs-built_in">int</span>)outputParam.Value;<br></code></pre></td></tr></table></figure><h3 id="8-自定义-EfCoreHelper-类，方便动态构建-Lambda-表达式进行查询，并执行分页、排序、过滤等数据库操作"><a href="#8-自定义-EfCoreHelper-类，方便动态构建-Lambda-表达式进行查询，并执行分页、排序、过滤等数据库操作" class="headerlink" title="8. 自定义 EfCoreHelper 类，方便动态构建 Lambda 表达式进行查询，并执行分页、排序、过滤等数据库操作"></a>8. 自定义 EfCoreHelper 类，方便动态构建 Lambda 表达式进行查询，并执行分页、排序、过滤等数据库操作</h3><h4 id="Sort-方法"><a href="#Sort-方法" class="headerlink" title="Sort 方法"></a>Sort 方法</h4><p>根据提供的 orderBy 字符串对 <code>IQueryable&lt;T&gt;</code> 集合进行排序。</p><h5 id="方法签名"><a href="#方法签名" class="headerlink" title="方法签名"></a>方法签名</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">Sort</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;T&gt; query, <span class="hljs-built_in">string</span> orderBy</span>)</span><br></code></pre></td></tr></table></figure><ul><li><code>query</code>: 要排序的 IQueryable 集合。</li><li><code>orderBy</code>: 以 “属性 方向” 格式表示的排序条件。</li></ul><h5 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> sortedQuery = dbContext.Users.Sort(<span class="hljs-string">&quot;Name ascending&quot;</span>);<br></code></pre></td></tr></table></figure><h4 id="Filter-方法"><a href="#Filter-方法" class="headerlink" title="Filter 方法"></a>Filter 方法</h4><p>根据提供的条件组列表对 <code>IQueryable&lt;T&gt;</code> 集合进行过滤。</p><h5 id="方法签名-1"><a href="#方法签名-1" class="headerlink" title="方法签名"></a>方法签名</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">Filter</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;T&gt; query, List&lt;ConditionGroup&gt;? groupedConditions</span>)</span><br></code></pre></td></tr></table></figure><ul><li><code>query</code>: 要过滤的 IQueryable 集合。</li><li><code>groupedConditions</code>: 要应用的条件组列表。</li></ul><h5 id="示例-1"><a href="#示例-1" class="headerlink" title="示例"></a>示例</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> filteredQuery = dbContext.Products.Filter(conditionGroups);<br></code></pre></td></tr></table></figure><h4 id="GetPageList-方法"><a href="#GetPageList-方法" class="headerlink" title="GetPageList 方法"></a>GetPageList 方法</h4><p>从数据库中检索元素的分页列表。</p><h5 id="方法签名-2"><a href="#方法签名-2" class="headerlink" title="方法签名"></a>方法签名</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Page</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">GetPageList</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, <span class="hljs-built_in">int</span> pageNumber, <span class="hljs-built_in">int</span> pageSize, <span class="hljs-built_in">string</span> orderBy = <span class="hljs-string">&quot;&quot;</span>, List&lt;ConditionGroup&gt;? conditionGroups = <span class="hljs-literal">null</span></span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br></code></pre></td></tr></table></figure><ul><li><code>context</code>: 数据库上下文。</li><li><code>pageNumber</code>: 要检索的页码。</li><li><code>pageSize</code>: 每页的大小。</li><li><code>orderBy</code>: 排序条件。</li><li><code>conditionGroups</code>: 用于过滤的条件组列表。</li></ul><h5 id="示例-2"><a href="#示例-2" class="headerlink" title="示例"></a>示例</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> page = EfCoreHelper.GetPageList&lt;User&gt;(dbContext, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-string">&quot;Name ascending&quot;</span>, conditionGroups);<br></code></pre></td></tr></table></figure><h4 id="GetPageListByNativeSql-方法"><a href="#GetPageListByNativeSql-方法" class="headerlink" title="GetPageListByNativeSql 方法"></a>GetPageListByNativeSql 方法</h4><p>使用本机 SQL 查询检索元素的分页列表。</p><h5 id="方法签名-3"><a href="#方法签名-3" class="headerlink" title="方法签名"></a>方法签名</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Page</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">GetPageListByNativeSql</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, <span class="hljs-built_in">string</span> sql, <span class="hljs-built_in">int</span> pageNumber, <span class="hljs-built_in">int</span> pageSize, <span class="hljs-built_in">string</span> orderBy = <span class="hljs-string">&quot;&quot;</span>, List&lt;ConditionGroup&gt;? conditionGroups = <span class="hljs-literal">null</span>, <span class="hljs-built_in">object</span>[]? sqlParameters = <span class="hljs-literal">null</span></span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br></code></pre></td></tr></table></figure><ul><li><code>context</code>: 数据库上下文。</li><li><code>sql</code>: SQL 查询。</li><li><code>pageNumber</code>: 要检索的页码。</li><li><code>pageSize</code>: 每页的大小。</li><li><code>orderBy</code>: 排序条件。</li><li><code>conditionGroups</code>: 用于过滤的条件组列表。</li><li><code>sqlParameters</code>: SQL 查询的可选参数。</li></ul><h5 id="示例-3"><a href="#示例-3" class="headerlink" title="示例"></a>示例</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> page = EfCoreHelper.GetPageListByNativeSql&lt;User&gt;(dbContext, <span class="hljs-string">&quot;SELECT * FROM Users&quot;</span>, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-string">&quot;Name ascending&quot;</span>, conditionGroups);<br></code></pre></td></tr></table></figure><h4 id="DeleteAll-方法"><a href="#DeleteAll-方法" class="headerlink" title="DeleteAll 方法"></a>DeleteAll 方法</h4><p>删除符合条件的所有记录。</p><h5 id="方法签名-4"><a href="#方法签名-4" class="headerlink" title="方法签名"></a>方法签名</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">int</span> <span class="hljs-title">DeleteAll</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, Expression&lt;Func&lt;T, <span class="hljs-built_in">bool</span>&gt;&gt; filter</span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br></code></pre></td></tr></table></figure><ul><li><code>context</code>: 数据库上下文。</li><li><code>filter</code>: 要应用的过滤器表达式。</li></ul><h5 id="示例-4"><a href="#示例-4" class="headerlink" title="示例"></a>示例</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> deletedCount = EfCoreHelper.DeleteAll&lt;User&gt;(dbContext, u =&gt; u.Age &gt; <span class="hljs-number">50</span>);<br></code></pre></td></tr></table></figure><h4 id="UpdateRecords-方法"><a href="#UpdateRecords-方法" class="headerlink" title="UpdateRecords 方法"></a>UpdateRecords 方法</h4><p>根据条件更新记录。</p><h5 id="方法签名-5"><a href="#方法签名-5" class="headerlink" title="方法签名"></a>方法签名</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">int</span> <span class="hljs-title">UpdateRecords</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, Func&lt;T, <span class="hljs-built_in">bool</span>&gt; predicate, Action&lt;T&gt; updateAction</span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br></code></pre></td></tr></table></figure><ul><li><code>context</code>: 数据库上下文。</li><li><code>predicate</code>: 要应用的条件谓词。</li><li><code>updateAction</code>: 更新记录的操作。</li></ul><h5 id="示例-5"><a href="#示例-5" class="headerlink" title="示例"></a>示例</h5><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">var</span> updatedCount = EfCoreHelper.UpdateRecords&lt;User&gt;(dbContext, u =&gt; u.IsActive, u =&gt; u.IsActive = <span class="hljs-literal">false</span>);<br></code></pre></td></tr></table></figure><h4 id="EfCoreHelper-完整代码"><a href="#EfCoreHelper-完整代码" class="headerlink" title="EfCoreHelper 完整代码"></a>EfCoreHelper 完整代码</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System.Linq.Expressions;<br><span class="hljs-keyword">using</span> System.Reflection;<br><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Common.Helpers</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EfCoreHelper</span><br>    &#123;<br>       <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Page</span>&lt;<span class="hljs-title">T</span>&gt;<br>       &#123;<br>           <span class="hljs-keyword">public</span> List&lt;T&gt; pageList &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>           <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> pageNumber &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>           <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> pageSize &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>           <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> total &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>           <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Page</span>()</span><br>           &#123;<br>               pageList = <span class="hljs-keyword">new</span> List&lt;T&gt;();<br>           &#125;<br>       &#125;<br>   <br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">Sort</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;T&gt; query, <span class="hljs-built_in">string</span> orderBy</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">string</span>.IsNullOrEmpty(orderBy))<br>            &#123;<br>                <span class="hljs-keyword">return</span> query;<br>            &#125;<br>            <span class="hljs-built_in">string</span>[] orderByParts = orderBy.Split(<span class="hljs-string">&#x27; &#x27;</span>);<br>            <span class="hljs-keyword">if</span> (orderByParts.Length == <span class="hljs-number">2</span>)<br>            &#123;<br>                <span class="hljs-built_in">string</span> column = orderByParts[<span class="hljs-number">0</span>].Trim();<br>                <span class="hljs-built_in">string</span> sort = orderByParts[<span class="hljs-number">1</span>].Trim().ToLower();<br><br>                <span class="hljs-comment">// 校验排序方式是否为 &quot;ascending&quot; 或 &quot;descending&quot;</span><br>                <span class="hljs-keyword">if</span> (sort == <span class="hljs-string">&quot;ascending&quot;</span> || sort == <span class="hljs-string">&quot;descending&quot;</span>)<br>                &#123;<br>                    <span class="hljs-comment">// 检查实体是否具有提供的列名属性</span><br>                    <span class="hljs-keyword">var</span> entityType = <span class="hljs-keyword">typeof</span>(T);<br>                    <span class="hljs-keyword">var</span> property = entityType.GetProperty(column);<br>                    <span class="hljs-keyword">if</span> (property != <span class="hljs-literal">null</span>)<br>                    &#123;<br>                        query = sort == <span class="hljs-string">&quot;ascending&quot;</span> ? query.OrderBy(t =&gt; EF.Property&lt;<span class="hljs-built_in">object</span>&gt;(t!, column))<br>                            : query.OrderByDescending(t =&gt; EF.Property&lt;<span class="hljs-built_in">object</span>&gt;(t!, column));<br>                    &#125;<br>                &#125;<br>            &#125;<br>            <span class="hljs-keyword">return</span> query;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Condition</span><br>        &#123;<br>            <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> PropertyName &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>            <span class="hljs-keyword">public</span> Comparison Comparison &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>            <span class="hljs-keyword">public</span> <span class="hljs-built_in">object</span>? Value &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>            <span class="hljs-keyword">public</span> <span class="hljs-built_in">object</span>? MinValue &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>            <span class="hljs-keyword">public</span> <span class="hljs-built_in">object</span>? MaxValue &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ConditionGroup</span><br>        &#123;<br>            <span class="hljs-keyword">public</span> List&lt;Condition&gt; Conditions &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>            <span class="hljs-keyword">public</span> LogicOperator Logic &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-built_in">enum</span> LogicOperator<br>        &#123;<br>            AND,<br>            OR<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-built_in">enum</span> Comparison<br>        &#123;<br>            Equal = <span class="hljs-number">1</span>,<br>            GreaterThan = <span class="hljs-number">2</span>,<br>            GreaterThanOrEqual = <span class="hljs-number">3</span>,<br>            LessThan = <span class="hljs-number">4</span>,<br>            LessThanOrEqual = <span class="hljs-number">5</span>,<br>            Contains = <span class="hljs-number">6</span>,<br>            StartWith = <span class="hljs-number">7</span>,<br>            EndWith = <span class="hljs-number">8</span>,<br>            Between = <span class="hljs-number">9</span><br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">Filter</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;T&gt; query, List&lt;ConditionGroup&gt;? groupedConditions</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">var</span> parameter = Expression.Parameter(<span class="hljs-keyword">typeof</span>(T), <span class="hljs-string">&quot;t&quot;</span>);<br>            List&lt;Expression&gt; groupExpressions = <span class="hljs-keyword">new</span> List&lt;Expression&gt;(); <span class="hljs-comment">// 用于存储所有分组的表达式</span><br><br>            <span class="hljs-keyword">if</span> (groupedConditions == <span class="hljs-literal">null</span>)<br>            &#123;<br>                <span class="hljs-keyword">return</span> query;<br>            &#125;<br><br>            <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> <span class="hljs-keyword">group</span> <span class="hljs-keyword">in</span> groupedConditions)<br>            &#123;<br>                List&lt;Condition&gt; conditions = <span class="hljs-keyword">group</span>.Conditions;<br>                LogicOperator groupLogic = <span class="hljs-keyword">group</span>.Logic;<br><br>                List&lt;Expression&gt; conditionExpressions = <span class="hljs-keyword">new</span> List&lt;Expression&gt;(); <span class="hljs-comment">// 用于存储每个分组内的条件表达式</span><br><br>                <span class="hljs-keyword">foreach</span> (Condition condition <span class="hljs-keyword">in</span> conditions)<br>                &#123;<br>                    Type type = <span class="hljs-keyword">typeof</span>(T);<br>                    PropertyInfo? propertyInfo = type.GetProperty(condition.PropertyName);<br>                    <span class="hljs-keyword">if</span> (propertyInfo == <span class="hljs-literal">null</span> ||<br>                        condition.Comparison != Comparison.Between &amp;&amp; condition.Value == <span class="hljs-literal">null</span> ||<br>                        condition.Comparison == Comparison.Between &amp;&amp; (condition.MinValue == <span class="hljs-literal">null</span> || condition.MaxValue == <span class="hljs-literal">null</span>) ||<br>                        condition.Value <span class="hljs-keyword">is</span> <span class="hljs-built_in">string</span> strValue &amp;&amp; <span class="hljs-built_in">string</span>.IsNullOrEmpty(strValue))<br>                    &#123;<br>                        <span class="hljs-keyword">continue</span>;<br>                    &#125;<br><br>                    Expression property = Expression.Property(parameter, propertyInfo);<br><br>                    Expression valueExpression = ConvertToPropertyType(condition.Value, propertyInfo.PropertyType);<br><br>                    Expression comparisonExpression;<br><br>                    <span class="hljs-keyword">switch</span> (condition.Comparison)<br>                    &#123;<br>                        <span class="hljs-keyword">case</span> Comparison.Equal:<br>                            comparisonExpression = Expression.Equal(property, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.GreaterThan:<br>                            comparisonExpression = Expression.GreaterThan(property, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.GreaterThanOrEqual:<br>                            comparisonExpression = Expression.GreaterThanOrEqual(property, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.LessThan:<br>                            comparisonExpression = Expression.LessThan(property, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.LessThanOrEqual:<br>                            comparisonExpression = Expression.LessThanOrEqual(property, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.Contains:<br>                            comparisonExpression = Expression.Call(property, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">string</span>).GetMethod(<span class="hljs-string">&quot;Contains&quot;</span>, <span class="hljs-keyword">new</span>[] &#123; <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">string</span>) &#125;)!, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.StartWith:<br>                            comparisonExpression = Expression.Call(property, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">string</span>).GetMethod(<span class="hljs-string">&quot;StartsWith&quot;</span>, <span class="hljs-keyword">new</span>[] &#123; <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">string</span>) &#125;)!, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.EndWith:<br>                            comparisonExpression = Expression.Call(property, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">string</span>).GetMethod(<span class="hljs-string">&quot;EndsWith&quot;</span>, <span class="hljs-keyword">new</span>[] &#123; <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">string</span>) &#125;)!, valueExpression);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-keyword">case</span> Comparison.Between:<br>                            Expression minValueExpression = ConvertToPropertyType(condition.MinValue, propertyInfo.PropertyType);<br>                            Expression maxValueExpression = ConvertToPropertyType(condition.MaxValue, propertyInfo.PropertyType);<br><br>                            <span class="hljs-keyword">var</span> min = Expression.GreaterThanOrEqual(property, minValueExpression);<br>                            <span class="hljs-keyword">var</span> max = Expression.LessThanOrEqual(property, maxValueExpression);<br><br>                            comparisonExpression = Expression.And(min, max);<br>                            <span class="hljs-keyword">break</span>;<br>                        <span class="hljs-literal">default</span>:<br>                            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">&quot;无效的比较运算符。&quot;</span>);<br>                    &#125;<br><br>                    conditionExpressions.Add(comparisonExpression);<br>                &#125;<br><br>                <span class="hljs-comment">// 根据分组的逻辑操作，将条件合并为总的表达式</span><br>                Expression? groupCombinedExpression = <span class="hljs-literal">null</span>;<br>                <span class="hljs-keyword">if</span> (conditionExpressions.Any())<br>                &#123;<br>                    groupCombinedExpression = conditionExpressions.Aggregate(groupLogic == LogicOperator.AND ? Expression.And : Expression.Or);<br>                &#125;<br>                <span class="hljs-keyword">if</span> (groupCombinedExpression != <span class="hljs-literal">null</span>)<br>                &#123;<br>                    groupExpressions.Add(groupCombinedExpression);<br>                &#125;<br>            &#125;<br><br>            <span class="hljs-comment">// 使用 AND 逻辑操作，合并所有分组表达式</span><br>            Expression? combinedExpression = <span class="hljs-literal">null</span>;<br>            <span class="hljs-keyword">if</span> (groupExpressions.Any())<br>            &#123;<br>                combinedExpression = groupExpressions.Aggregate(Expression.And);<br>            &#125;<br><br>            <span class="hljs-comment">// 如果没有任何条件，则返回原始查询</span><br>            <span class="hljs-keyword">if</span> (combinedExpression == <span class="hljs-literal">null</span>)<br>            &#123;<br>                <span class="hljs-keyword">return</span> query;<br>            &#125;<br>            <span class="hljs-comment">// 构建 Lambda 表达式，并将其应用到查询上</span><br>            <span class="hljs-keyword">var</span> lambdaExpression = Expression.Lambda&lt;Func&lt;T, <span class="hljs-built_in">bool</span>&gt;&gt;(combinedExpression, parameter);<br>            <span class="hljs-keyword">var</span> expressionString = lambdaExpression.ToString();<br><br>            <span class="hljs-keyword">return</span> query.Where(lambdaExpression);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Expression <span class="hljs-title">ConvertToPropertyType</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">T <span class="hljs-keyword">value</span>, Type propertyType</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> Expression.Constant(<span class="hljs-keyword">value</span>, propertyType);<br>        &#125;<br><br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Page</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">GetPageList</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, <span class="hljs-built_in">int</span> pageNumber, <span class="hljs-built_in">int</span> pageSize, <span class="hljs-built_in">string</span> orderBy = <span class="hljs-string">&quot;&quot;</span>, List&lt;ConditionGroup&gt;? conditionGroups = <span class="hljs-literal">null</span></span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br>        &#123;<br>            <span class="hljs-keyword">var</span> query = context.Set&lt;T&gt;().AsQueryable().Filter(conditionGroups).Sort(orderBy);<br>            <span class="hljs-keyword">var</span> totalCount = query.Count();<br>            <span class="hljs-keyword">var</span> pageList = query.Skip((pageNumber - <span class="hljs-number">1</span>) * pageSize).Take(pageSize).ToList();<br><br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Page&lt;T&gt;<br>            &#123;<br>                pageList = pageList,<br>                pageNumber = pageNumber,<br>                pageSize = pageSize,<br>                total = totalCount<br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Page</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">GetPageListByNativeSql</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, <span class="hljs-built_in">string</span> sql, <span class="hljs-built_in">int</span> pageNumber, <span class="hljs-built_in">int</span> pageSize, <span class="hljs-built_in">string</span> orderBy = <span class="hljs-string">&quot;&quot;</span>, List&lt;ConditionGroup&gt;? conditionGroups = <span class="hljs-literal">null</span>, <span class="hljs-built_in">object</span>[]? sqlParameters = <span class="hljs-literal">null</span></span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br>        &#123;<br>            IQueryable&lt;T&gt; query;<br><br>            <span class="hljs-keyword">if</span> (sqlParameters != <span class="hljs-literal">null</span>)<br>            &#123;<br>                query = context.Set&lt;T&gt;().FromSqlRaw(sql, sqlParameters);<br>            &#125;<br>            <span class="hljs-keyword">else</span><br>            &#123;<br>                query = context.Set&lt;T&gt;().FromSqlRaw(sql);<br>            &#125;<br><br>            query = query.Filter(conditionGroups).Sort(orderBy);<br><br>            <span class="hljs-keyword">var</span> totalCount = query.Count();<br>            <span class="hljs-keyword">var</span> pageList = query.Skip((pageNumber - <span class="hljs-number">1</span>) * pageSize).Take(pageSize).ToList();<br><br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Page&lt;T&gt;<br>            &#123;<br>                pageList = pageList,<br>                pageNumber = pageNumber,<br>                pageSize = pageSize,<br>                total = totalCount<br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">int</span> <span class="hljs-title">DeleteAll</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, Expression&lt;Func&lt;T, <span class="hljs-built_in">bool</span>&gt;&gt; filter</span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br>        &#123;<br>            <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> transaction = context.Database.BeginTransaction())<br>            &#123;<br>                <span class="hljs-keyword">var</span> recordsToDelete = context.Set&lt;T&gt;().Where(filter).ToList();<br><br>                <span class="hljs-keyword">if</span> (recordsToDelete.Any())<br>                &#123;<br>                    context.Set&lt;T&gt;().RemoveRange(recordsToDelete);<br>                    <span class="hljs-built_in">int</span> affectedRows = context.SaveChanges();<br><br>                    <span class="hljs-keyword">if</span> (affectedRows != recordsToDelete.Count)<br>                    &#123;<br>                        transaction.Rollback();<br>                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$&quot;部分数据删除失败，总共 <span class="hljs-subst">&#123;recordsToDelete.Count&#125;</span> 条，删除 <span class="hljs-subst">&#123;affectedRows&#125;</span> 条记录，进行回滚&quot;</span>);<br>                    &#125;<br><br>                    transaction.Commit();<br><br>                    <span class="hljs-keyword">return</span> affectedRows;<br>                &#125;<br>                <span class="hljs-keyword">else</span><br>                &#123;<br>                    transaction.Rollback();<br>                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$&quot;数据库查询不到符合条件的记录&quot;</span>);<br>                &#125;<br>            &#125;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">int</span> <span class="hljs-title">UpdateRecords</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">DbContext context, Func&lt;T, <span class="hljs-built_in">bool</span>&gt; predicate, Action&lt;T&gt; updateAction</span>) <span class="hljs-keyword">where</span> T : <span class="hljs-keyword">class</span></span><br>        &#123;<br>            <span class="hljs-built_in">int</span> affectedRows = <span class="hljs-number">0</span>;<br><br>            <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> transaction = context.Database.BeginTransaction())<br>            &#123;<br>                <span class="hljs-keyword">var</span> recordsToUpdate = context.Set&lt;T&gt;().Where(predicate).ToList();<br><br>                <span class="hljs-keyword">if</span> (recordsToUpdate.Any())<br>                &#123;<br>                    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> <span class="hljs-keyword">record</span> <span class="hljs-title">in</span> <span class="hljs-title">recordsToUpdate</span>)<br>                    &#123;<br>                        updateAction(<span class="hljs-keyword">record</span>);<br>                    &#125;<br><br>                    affectedRows = context.SaveChanges();<br><br>                    <span class="hljs-keyword">if</span> (affectedRows &gt; <span class="hljs-number">0</span>)<br>                    &#123;<br>                        transaction.Commit();<br>                    &#125;<br>                    <span class="hljs-keyword">else</span><br>                    &#123;<br>                        transaction.Rollback();<br>                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">&quot;更新操作未能影响任何记录&quot;</span>);<br>                    &#125;<br>                &#125;<br>                <span class="hljs-keyword">else</span><br>                &#123;<br>                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">&quot;数据库查询不到符合条件的记录&quot;</span>);<br>                &#125;<br>            &#125;<br>            <span class="hljs-keyword">return</span> affectedRows;<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="十、使用-AutoMapper-进行对象映射"><a href="#十、使用-AutoMapper-进行对象映射" class="headerlink" title="十、使用 AutoMapper 进行对象映射"></a>十、使用 AutoMapper 进行对象映射</h2><p>AutoMapper 是一个自动执行对象到对象之间的映射的工具，用于简化在不同层之间的对象转换。在 ASP.NET Core 中，AutoMapper Profile 是用于配置和定义映射规则的类。通过继承 <code>Profile</code> 类，你可以集中管理所有映射配置，保持代码清晰和易维护。</p><h3 id="1-安装-AutoMapper"><a href="#1-安装-AutoMapper" class="headerlink" title="1. 安装 AutoMapper"></a>1. 安装 AutoMapper</h3><p>要在 ASP.NET Core 项目中使用 AutoMapper，你需要安装两个 NuGet 包：<code>AutoMapper</code> 和 <code>AutoMapper.Extensions.Microsoft.DependencyInjection</code>。</p><p><strong>使用 NuGet 包管理器控制台：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">Install-Package AutoMapper<br></code></pre></td></tr></table></figure><p><strong>使用 .NET CLI：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet add package AutoMapper<br></code></pre></td></tr></table></figure><h3 id="2-配置-AutoMapper-Profile"><a href="#2-配置-AutoMapper-Profile" class="headerlink" title="2. 配置 AutoMapper Profile"></a>2. 配置 AutoMapper Profile</h3><p>创建一个继承自 <code>Profile</code> 的类，在其中定义对象之间的映射规则。</p><p><strong>示例：DtoMapper.cs</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> AutoMapper;<br><span class="hljs-keyword">using</span> Loquy.Dtos;<br><span class="hljs-keyword">using</span> Loquy.Models;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Services.Mapper</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DtoMapper</span> : <span class="hljs-title">Profile</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DtoMapper</span>()</span><br>        &#123;<br>            CreateMap&lt;User, UserDto&gt;();<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在这个示例中，<code>DtoMapper</code> 类定义了从 <code>User</code> 到 <code>UserDto</code> 的映射规则。</p><h3 id="3-创建自定义扩展方法注册-AutoMapper"><a href="#3-创建自定义扩展方法注册-AutoMapper" class="headerlink" title="3. 创建自定义扩展方法注册 AutoMapper"></a>3. 创建自定义扩展方法注册 AutoMapper</h3><p>为了简化 AutoMapper 的注册过程，可以创建自定义扩展方法。</p><p><strong>示例：ServiceCollectionExtensions.cs</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> AutoMapper;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Services.Extensions</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ServiceCollectionExtensions</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddCustomAutoMapper</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">var</span> mapperConfiguration = <span class="hljs-keyword">new</span> MapperConfiguration(cfg =&gt;<br>            &#123;<br>                cfg.AddProfile&lt;DtoMapper&gt;();<br>            &#125;);<br><br>            IMapper mapper = mapperConfiguration.CreateMapper();<br>            services.AddSingleton(mapper);<br><br>            <span class="hljs-keyword">return</span> services;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在这个示例中，<code>AddCustomAutoMapper</code> 方法配置了 AutoMapper，并将其注册为单例服务。</p><h3 id="4-在-Startup-cs-中注册-AutoMapper"><a href="#4-在-Startup-cs-中注册-AutoMapper" class="headerlink" title="4. 在 Startup.cs 中注册 AutoMapper"></a>4. 在 Startup.cs 中注册 AutoMapper</h3><p>在 <code>Startup.cs</code> 文件的 <code>ConfigureServices</code> 方法中调用我们定义的扩展方法来注册 AutoMapper。</p><p><strong>示例：Startup.cs</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 注册 Services</span><br>    services.AddDependencyGroup();<br>    <span class="hljs-comment">// 注册 AutoMapper</span><br>    services.AddCustomAutoMapper();<br><br>    <span class="hljs-comment">// 其他服务注册</span><br>&#125;<br></code></pre></td></tr></table></figure><p>通过这样的方法，我们可以将 AutoMapper 的配置和注册逻辑分离到独立的扩展方法中，使得 <code>Startup.cs</code> 文件更加简洁。</p><h3 id="5-使用-AutoMapper"><a href="#5-使用-AutoMapper" class="headerlink" title="5. 使用 AutoMapper"></a>5. 使用 AutoMapper</h3><p>现在你可以在你的控制器或服务中使用 AutoMapper 进行对象映射。你只需要通过构造函数注入 <code>IMapper</code> 接口，并使用 <code>Map</code> 方法进行对象转换。</p><p><strong>示例：UsersController.cs</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> AutoMapper;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UsersController</span> : <span class="hljs-title">ControllerBase</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMapper _mapper;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UsersController</span>(<span class="hljs-params">IMapper mapper</span>)</span><br>    &#123;<br>        _mapper = mapper;<br>    &#125;<br><br>    [<span class="hljs-meta">HttpGet(<span class="hljs-string">&quot;&#123;id&#125;&quot;</span>)</span>]<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult&lt;UserDto&gt; <span class="hljs-title">GetUser</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> id</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 模拟从数据库获取用户</span><br>        User user = GetUserById(id);<br><br>        <span class="hljs-comment">// 使用 AutoMapper 将 User 转换为 UserDto</span><br>        UserDto userDto = _mapper.Map&lt;UserDto&gt;(user);<br><br>        <span class="hljs-keyword">return</span> Ok(userDto);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> User <span class="hljs-title">GetUserById</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> id</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 模拟数据获取</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> User &#123; Id = id, FirstName = <span class="hljs-string">&quot;John&quot;</span>, LastName = <span class="hljs-string">&quot;Doe&quot;</span> &#125;;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在这个示例中，通过构造函数注入 <code>IMapper</code> 实例，并使用 <code>_mapper.Map&lt;UserDto&gt;(user)</code> 将 <code>User</code> 对象转换为 <code>UserDto</code> 对象。</p><h2 id="十一、使用-JWTBearer-进行身份验证"><a href="#十一、使用-JWTBearer-进行身份验证" class="headerlink" title="十一、使用 JWTBearer 进行身份验证"></a>十一、使用 JWTBearer 进行身份验证</h2><h3 id="1-安装所需的包：首先，你需要安装必要的-NuGet-包。"><a href="#1-安装所需的包：首先，你需要安装必要的-NuGet-包。" class="headerlink" title="1. 安装所需的包：首先，你需要安装必要的 NuGet 包。"></a>1. <strong>安装所需的包</strong>：首先，你需要安装必要的 NuGet 包。</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer<br></code></pre></td></tr></table></figure><h3 id="2-配置-JWTBearer-身份验证：在-Startup-cs-文件的-ConfigureServices-方法中配置-JWTBearer-身份验证，并读取-appsettings-json-提供的配置。"><a href="#2-配置-JWTBearer-身份验证：在-Startup-cs-文件的-ConfigureServices-方法中配置-JWTBearer-身份验证，并读取-appsettings-json-提供的配置。" class="headerlink" title="2. 配置 JWTBearer 身份验证：在 Startup.cs 文件的 ConfigureServices 方法中配置 JWTBearer 身份验证，并读取 appsettings.json 提供的配置。"></a>2. <strong>配置 JWTBearer 身份验证</strong>：在 <code>Startup.cs</code> 文件的 <code>ConfigureServices</code> 方法中配置 JWTBearer 身份验证，并读取 <code>appsettings.json</code> 提供的配置。</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span><br>  <span class="hljs-attr">&quot;JwtSettings&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;SecretKey&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;YourSecretKeyHere&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;Issuer&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;YourIssuerHere&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;Audience&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;YourAudienceHere&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;ExpirationMinutes&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">30</span> <span class="hljs-comment">// 令牌过期时间，单位为分钟</span><br>  <span class="hljs-punctuation">&#125;</span><br><span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Authentication.JwtBearer;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.Configuration;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection;<br><span class="hljs-keyword">using</span> Microsoft.IdentityModel.Tokens;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Text;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span><br>&#123;<br>    <span class="hljs-keyword">public</span> IConfiguration Configuration &#123; <span class="hljs-keyword">get</span>; &#125;<br><br>    <span class="hljs-comment">// 构造函数，接收 IConfiguration 对象用于读取配置</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Startup</span>(<span class="hljs-params">IConfiguration configuration</span>)</span><br>    &#123;<br>        Configuration = configuration;<br>    &#125;<br><br>    <span class="hljs-comment">// 配置服务</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 从配置中读取 JWT 相关设置</span><br>        <span class="hljs-keyword">var</span> jwtSettings = Configuration.GetSection(<span class="hljs-string">&quot;JwtSettings&quot;</span>);<br><br>        <span class="hljs-comment">// 从配置中获取密钥、发布者、订阅者和令牌过期时间</span><br>        <span class="hljs-keyword">var</span> secretKey = jwtSettings[<span class="hljs-string">&quot;SecretKey&quot;</span>];<br>        <span class="hljs-keyword">var</span> issuer = jwtSettings[<span class="hljs-string">&quot;Issuer&quot;</span>];<br>        <span class="hljs-keyword">var</span> audience = jwtSettings[<span class="hljs-string">&quot;Audience&quot;</span>];<br>        <span class="hljs-keyword">var</span> expirationMinutes = Convert.ToInt32(jwtSettings[<span class="hljs-string">&quot;ExpirationMinutes&quot;</span>]);<br><br>        <span class="hljs-comment">// 添加身份验证服务</span><br>        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)<br>            .AddJwtBearer(options =&gt;<br>            &#123;<br>                <span class="hljs-comment">// 设置令牌验证参数</span><br>                options.TokenValidationParameters = <span class="hljs-keyword">new</span> TokenValidationParameters<br>                &#123;<br>                    ValidateIssuer = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证发布者</span><br>                    ValidateAudience = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证订阅者</span><br>                    ValidateLifetime = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证令牌生命周期</span><br>                    ValidateIssuerSigningKey = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证签名密钥</span><br>                    ValidIssuer = issuer, <span class="hljs-comment">// 设置有效的发布者</span><br>                    ValidAudience = audience, <span class="hljs-comment">// 设置有效的订阅者</span><br>                    IssuerSigningKey = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), <span class="hljs-comment">// 设置签名密钥</span><br>                    ClockSkew = TimeSpan.Zero <span class="hljs-comment">// 不允许任何时钟偏差</span><br>                &#125;;<br>            &#125;);<br><br>        <span class="hljs-comment">// 添加控制器服务</span><br>        services.AddControllers();<br>    &#125;<br><br>    <span class="hljs-comment">// 配置应用程序请求管道</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app, IWebHostEnvironment env</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 省略其他配置...</span><br><br>        <span class="hljs-comment">// 使用身份验证中间件</span><br>        app.UseAuthentication();<br>        app.UseAuthorization();<br><br>        <span class="hljs-comment">// 配置端点路由</span><br>        app.UseEndpoints(endpoints =&gt;<br>        &#123;<br>            endpoints.MapControllers();<br>        &#125;);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-保护你的-API-端点：在需要保护的-API-控制器或方法上使用-Authorize-特性。"><a href="#3-保护你的-API-端点：在需要保护的-API-控制器或方法上使用-Authorize-特性。" class="headerlink" title="3. 保护你的 API 端点：在需要保护的 API 控制器或方法上使用 [Authorize] 特性。"></a>3. <strong>保护你的 API 端点</strong>：在需要保护的 API 控制器或方法上使用 <code>[Authorize]</code> 特性。</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Authorization;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;<br><br>[<span class="hljs-meta">Authorize</span>]<br>[<span class="hljs-meta">ApiController</span>]<br>[<span class="hljs-meta">Route(<span class="hljs-string">&quot;api/[controller]&quot;</span>)</span>]<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">YourController</span> : <span class="hljs-title">ControllerBase</span><br>&#123;<br>    <span class="hljs-comment">// 你的受保护 API 端点</span><br>&#125;<br></code></pre></td></tr></table></figure><h3 id="4-生成和验证-JWT-令牌：当需要生成-JWT-令牌时，你可以使用-System-IdentityModel-Tokens-Jwt-或其他相关库。你可以使用提供的配置中的过期时间来设置令牌的有效期。"><a href="#4-生成和验证-JWT-令牌：当需要生成-JWT-令牌时，你可以使用-System-IdentityModel-Tokens-Jwt-或其他相关库。你可以使用提供的配置中的过期时间来设置令牌的有效期。" class="headerlink" title="4. 生成和验证 JWT 令牌：当需要生成 JWT 令牌时，你可以使用 System.IdentityModel.Tokens.Jwt 或其他相关库。你可以使用提供的配置中的过期时间来设置令牌的有效期。"></a>4. <strong>生成和验证 JWT 令牌</strong>：当需要生成 JWT 令牌时，你可以使用 <code>System.IdentityModel.Tokens.Jwt</code> 或其他相关库。你可以使用提供的配置中的过期时间来设置令牌的有效期。</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Microsoft.IdentityModel.Tokens;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.IdentityModel.Tokens.Jwt;<br><span class="hljs-keyword">using</span> System.Security.Claims;<br><span class="hljs-keyword">using</span> System.Text;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TokenService</span><br>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration _configuration;<br><br>    <span class="hljs-comment">// 构造函数，接收 IConfiguration 对象用于读取配置</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TokenService</span>(<span class="hljs-params">IConfiguration configuration</span>)</span><br>    &#123;<br>        _configuration = configuration;<br>    &#125;<br><br>    <span class="hljs-comment">// 生成 JWT 令牌</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GenerateToken</span>()</span><br>    &#123;<br>        <span class="hljs-comment">// 从配置中获取 JWT 相关设置</span><br>        <span class="hljs-keyword">var</span> jwtSettings = _configuration.GetSection(<span class="hljs-string">&quot;JwtSettings&quot;</span>);<br><br>        <span class="hljs-comment">// 创建 JWT 令牌处理器</span><br>        <span class="hljs-keyword">var</span> tokenHandler = <span class="hljs-keyword">new</span> JwtSecurityTokenHandler();<br>        <span class="hljs-comment">// 从配置中获取密钥，并转换为字节数组</span><br>        <span class="hljs-keyword">var</span> secretKey = jwtSettings[<span class="hljs-string">&quot;SecretKey&quot;</span>];<br>        <span class="hljs-keyword">var</span> key = Encoding.ASCII.GetBytes(secretKey);<br>        <span class="hljs-comment">// 获取发布者和订阅者信息</span><br>        <span class="hljs-keyword">var</span> issuer = jwtSettings[<span class="hljs-string">&quot;Issuer&quot;</span>];<br>        <span class="hljs-keyword">var</span> audience = jwtSettings[<span class="hljs-string">&quot;Audience&quot;</span>];<br>        <span class="hljs-comment">// 获取令牌过期时间（分钟）</span><br>        <span class="hljs-keyword">var</span> expirationMinutes = Convert.ToInt32(jwtSettings[<span class="hljs-string">&quot;ExpirationMinutes&quot;</span>]);<br><br>        <span class="hljs-comment">// 构建令牌描述信息</span><br>        <span class="hljs-keyword">var</span> tokenDescriptor = <span class="hljs-keyword">new</span> SecurityTokenDescriptor<br>        &#123;<br>            <span class="hljs-comment">// 设置主题，这里可以添加用户声明等信息</span><br>            Subject = <span class="hljs-keyword">new</span> ClaimsIdentity(<span class="hljs-keyword">new</span> Claim[]<br>            &#123;<br>                <span class="hljs-keyword">new</span> Claim(ClaimTypes.Name, <span class="hljs-string">&quot;username&quot;</span>),<br>                <span class="hljs-comment">// 添加其他声明</span><br>            &#125;),<br>            <span class="hljs-comment">// 设置令牌过期时间</span><br>            Expires = DateTime.UtcNow.AddMinutes(expirationMinutes),<br>            <span class="hljs-comment">// 设置令牌的订阅者信息</span><br>            Audience = audience,<br>            <span class="hljs-comment">// 设置令牌的发布者信息</span><br>            Issuer = issuer,<br>            <span class="hljs-comment">// 设置签名凭据，使用对称密钥进行签名</span><br>            SigningCredentials = <span class="hljs-keyword">new</span> SigningCredentials(<span class="hljs-keyword">new</span> SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)<br>        &#125;;<br><br>        <span class="hljs-comment">// 创建 JWT 令牌</span><br>        <span class="hljs-keyword">var</span> token = tokenHandler.CreateToken(tokenDescriptor);<br>        <span class="hljs-comment">// 将令牌序列化为字符串并返回</span><br>        <span class="hljs-keyword">return</span> tokenHandler.WriteToken(token);<br>    &#125;<br><br>    <span class="hljs-comment">// 从令牌中解析出用户主体</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ClaimsPrincipal <span class="hljs-title">GetPrincipalFromToken</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> token</span>)</span><br>    &#123;<br>        <span class="hljs-comment">// 创建 JWT 令牌处理器</span><br>        <span class="hljs-keyword">var</span> tokenHandler = <span class="hljs-keyword">new</span> JwtSecurityTokenHandler();<br>        <span class="hljs-comment">// 从配置中获取 JWT 相关设置</span><br>        <span class="hljs-keyword">var</span> jwtSettings = _configuration.GetSection(<span class="hljs-string">&quot;JwtSettings&quot;</span>);<br>        <span class="hljs-comment">// 从配置中获取密钥，并转换为字节数组</span><br>        <span class="hljs-keyword">var</span> secretKey = jwtSettings[<span class="hljs-string">&quot;SecretKey&quot;</span>];<br>        <span class="hljs-keyword">var</span> key = Encoding.ASCII.GetBytes(secretKey);<br><br>        <span class="hljs-keyword">try</span><br>        &#123;<br>            <span class="hljs-comment">// 设置令牌验证参数</span><br>            <span class="hljs-keyword">var</span> tokenValidationParameters = <span class="hljs-keyword">new</span> TokenValidationParameters<br>            &#123;<br>                ValidateIssuerSigningKey = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证签名密钥</span><br>                IssuerSigningKey = <span class="hljs-keyword">new</span> SymmetricSecurityKey(key), <span class="hljs-comment">// 设置签名密钥</span><br>                ValidateIssuer = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证发布者信息</span><br>                ValidIssuer = jwtSettings[<span class="hljs-string">&quot;Issuer&quot;</span>], <span class="hljs-comment">// 设置有效的发布者</span><br>                ValidateAudience = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证订阅者信息</span><br>                ValidAudience = jwtSettings[<span class="hljs-string">&quot;Audience&quot;</span>], <span class="hljs-comment">// 设置有效的订阅者</span><br>                ValidateLifetime = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 验证令牌的生命周期</span><br>                ClockSkew = TimeSpan.Zero <span class="hljs-comment">// 不允许任何时钟偏差</span><br>            &#125;;<br><br>            <span class="hljs-comment">// 验证令牌并获取用户主体信息</span><br>            <span class="hljs-keyword">var</span> principal = tokenHandler.ValidateToken(token, tokenValidationParameters, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> validatedToken);<br>            <span class="hljs-comment">// 返回用户主体信息</span><br>            <span class="hljs-keyword">return</span> principal;<br>        &#125;<br>        <span class="hljs-keyword">catch</span><br>        &#123;<br>            <span class="hljs-comment">// 令牌无效，返回 null</span><br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="5-实际使用示例"><a href="#5-实际使用示例" class="headerlink" title="5. 实际使用示例"></a>5. 实际使用示例</h3><h4 id="5-1-通用返回格式"><a href="#5-1-通用返回格式" class="headerlink" title="5.1 通用返回格式"></a>5.1 通用返回格式</h4><p>统一后端返回结果</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Common.Dtos.Base</span><br>&#123;<br>    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span><br>    <span class="hljs-comment"><span class="hljs-doctag">///</span> 通用返回结果</span><br>    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span><br>    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;typeparam name=&quot;T&quot;&gt;</span><span class="hljs-doctag">&lt;/typeparam&gt;</span></span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ResultModel</span>&lt;<span class="hljs-title">T</span>&gt;<br>    &#123;<br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> 代码（0成功，-1失败）</span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span><br>        <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> code &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> 消息</span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span><br>        <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> message &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> 数据</span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span><br>        <span class="hljs-keyword">public</span> T? data &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ResultModel</span>()</span><br>        &#123;<br>            <span class="hljs-comment">// 默认构造函数</span><br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Success</span>()</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = ResultEnums.SUCCESS.code,<br>                message = ResultEnums.SUCCESS.message,<br>                data = <span class="hljs-literal">default</span><br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Success</span>(<span class="hljs-params">T data</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = ResultEnums.SUCCESS.code,<br>                message = ResultEnums.SUCCESS.message,<br>                data = data<br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Success</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> message</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = ResultEnums.SUCCESS.code,<br>                message = message,<br>                data = <span class="hljs-literal">default</span><br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Success</span>(<span class="hljs-params">T data, <span class="hljs-built_in">string</span> message</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = ResultEnums.SUCCESS.code,<br>                message = message,<br>                data = data<br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Fail</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> message</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = ResultEnums.FAIL.code,<br>                message = message,<br>                data = <span class="hljs-literal">default</span><br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Fail</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> code, <span class="hljs-built_in">string</span> message</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = code,<br>                message = message,<br>                data = <span class="hljs-literal">default</span><br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ResultModel&lt;T&gt; <span class="hljs-title">Fail</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> code, <span class="hljs-built_in">string</span> message, T data</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ResultModel&lt;T&gt;<br>            &#123;<br>                code = code,<br>                message = message,<br>                data = data<br>            &#125;;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ResultEnums</span><br>        &#123;<br>            <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> ResultEnums FAIL = <span class="hljs-keyword">new</span> ResultEnums(<span class="hljs-number">-1</span>, <span class="hljs-string">&quot;失败&quot;</span>);<br><br>            <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> ResultEnums SUCCESS = <span class="hljs-keyword">new</span> ResultEnums(<span class="hljs-number">0</span>, <span class="hljs-string">&quot;成功&quot;</span>);<br><br>            <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> code &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; &#125;<br><br>            <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> message &#123; <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; &#125;<br><br>            <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">ResultEnums</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> code, <span class="hljs-built_in">string</span> message</span>)</span><br>            &#123;<br>                <span class="hljs-keyword">this</span>.code = code;<br>                <span class="hljs-keyword">this</span>.message = message;<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h4 id="5-2-封装-JWT工具类"><a href="#5-2-封装-JWT工具类" class="headerlink" title="5.2 封装 JWT工具类"></a>5.2 封装 JWT工具类</h4><p>JWT 工具类接口，可注入到其他服务使用</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Loquy.Common.WMS.Dtos.UserMan;<br><span class="hljs-keyword">using</span> Loquy.Models;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Common.Authorization</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IJwtUtils</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-built_in">string</span> <span class="hljs-title">GenerateJwtToken</span>(<span class="hljs-params">User user</span>)</span>;<br>        <span class="hljs-built_in">string</span>? ValidateJwtToken(<span class="hljs-built_in">string</span>? token);<br>        <span class="hljs-built_in">string</span>? GetCurrentToken();<br>        User? GetUserByToken();<br>        User? GetCurrentUser();<br>        <span class="hljs-function"><span class="hljs-built_in">int</span> <span class="hljs-title">GetExpiresMinutes</span>()</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>JWT 工具类实现类，提供方法：根据用户生成 Token、验证 Token、获取当前 Token、根据 Token 获取用户、获取当前用户、获取 Token 过期分钟数</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System.IdentityModel.Tokens.Jwt;<br><span class="hljs-keyword">using</span> System.Security.Claims;<br><span class="hljs-keyword">using</span> System.Text;<br><span class="hljs-keyword">using</span> Loquy.Common.WMS.Dtos.UserMan;<br><span class="hljs-keyword">using</span> Loquy.Models;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Http;<br><span class="hljs-keyword">using</span> Microsoft.Extensions.Configuration;<br><span class="hljs-keyword">using</span> Microsoft.IdentityModel.Tokens;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Common.Authorization</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">JwtUtils</span> : <span class="hljs-title">IJwtUtils</span><br>    &#123;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration _configuration;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IHttpContextAccessor _httpContextAccessor;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> AppDbContext _context;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">JwtUtils</span>(<span class="hljs-params">IConfiguration configuration, IHttpContextAccessor httpContextAccessor, AppDbContext context</span>)</span><br>        &#123;<br>            _configuration = configuration;<br>            _httpContextAccessor = httpContextAccessor;<br>            _context = context;<br><br>            <span class="hljs-built_in">string</span> secret = _configuration[<span class="hljs-string">&quot;JwtSettings:SecretKey&quot;</span>] ?? <span class="hljs-string">&quot;&quot;</span>;<br>            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">string</span>.IsNullOrEmpty(secret))<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">&quot;未配置 JWT 密钥&quot;</span>);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GenerateJwtToken</span>(<span class="hljs-params">User user</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">var</span> tokenHandler = <span class="hljs-keyword">new</span> JwtSecurityTokenHandler();<br>            <span class="hljs-keyword">var</span> key = Encoding.ASCII.GetBytes(_configuration[<span class="hljs-string">&quot;JwtSettings:SecretKey&quot;</span>]!);<br>            <span class="hljs-keyword">var</span> tokenDescriptor = <span class="hljs-keyword">new</span> SecurityTokenDescriptor<br>            &#123;<br>                Subject = <span class="hljs-keyword">new</span> ClaimsIdentity(<span class="hljs-keyword">new</span>[] &#123; <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">&quot;id&quot;</span>, user.id.ToString()) &#125;),<br>                Expires = DateTime.UtcNow.AddMinutes(Convert.ToInt32(_configuration[<span class="hljs-string">&quot;JwtSettings:ExpirationMinutes&quot;</span>])),<br>                Issuer = _configuration[<span class="hljs-string">&quot;JwtSettings:Issuer&quot;</span>],<br>                Audience = _configuration[<span class="hljs-string">&quot;JwtSettings:Audience&quot;</span>],<br>                SigningCredentials = <span class="hljs-keyword">new</span> SigningCredentials(<span class="hljs-keyword">new</span> SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)<br>            &#125;;<br>            <span class="hljs-keyword">var</span> token = tokenHandler.CreateToken(tokenDescriptor);<br>            <span class="hljs-keyword">return</span> tokenHandler.WriteToken(token);<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span>? ValidateJwtToken(<span class="hljs-built_in">string</span>? token)<br>        &#123;<br>            <span class="hljs-keyword">if</span> (token == <span class="hljs-literal">null</span>)<br>                <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br><br>            <span class="hljs-keyword">var</span> tokenHandler = <span class="hljs-keyword">new</span> JwtSecurityTokenHandler();<br>            <span class="hljs-keyword">var</span> key = Encoding.ASCII.GetBytes(_configuration[<span class="hljs-string">&quot;Secret:SecretKey&quot;</span>]!);<br>            <span class="hljs-keyword">try</span><br>            &#123;<br>                tokenHandler.ValidateToken(token, <span class="hljs-keyword">new</span> TokenValidationParameters<br>                &#123;<br>                    ValidateIssuerSigningKey = <span class="hljs-literal">true</span>,<br>                    IssuerSigningKey = <span class="hljs-keyword">new</span> SymmetricSecurityKey(key),<br>                    ValidateIssuer = <span class="hljs-literal">true</span>,<br>                    ValidateAudience = <span class="hljs-literal">true</span>,<br>                    ValidIssuer = _configuration[<span class="hljs-string">&quot;JwtSettings:Issuer&quot;</span>], <br>                    ValidAudience = _configuration[<span class="hljs-string">&quot;JwtSettings:Audience&quot;</span>], <br>                    <span class="hljs-comment">// 将clockskew设置为0，这样令牌就会在令牌过期时间过期(而不是5分钟后)</span><br>                    ClockSkew = TimeSpan.Zero<br>                &#125;, <span class="hljs-keyword">out</span> SecurityToken validatedToken);<br><br>                <span class="hljs-keyword">var</span> jwtToken = (JwtSecurityToken)validatedToken;<br>                <span class="hljs-keyword">var</span> userId = jwtToken.Claims.First(x =&gt; x.Type == <span class="hljs-string">&quot;id&quot;</span>).Value;<br><br>                <span class="hljs-comment">// 如果验证成功，则从JWT令牌返回用户id</span><br>                <span class="hljs-keyword">return</span> userId;<br>            &#125;<br>            <span class="hljs-keyword">catch</span><br>            &#123;<br>                <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>            &#125;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span>? GetCurrentToken()<br>        &#123;<br>            <span class="hljs-built_in">string</span>? token = _httpContextAccessor.HttpContext?.Request.Headers[<span class="hljs-string">&quot;Authorization&quot;</span>].FirstOrDefault()?.Split(<span class="hljs-string">&quot; &quot;</span>).Last();<br>            <span class="hljs-keyword">return</span> token;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> User? GetUserByToken()<br>        &#123;<br>            <span class="hljs-built_in">string</span>? token = GetCurrentToken();<br>            <span class="hljs-built_in">string</span>? userId = ValidateJwtToken(token);<br>            User? user = _context.User.Where(u =&gt; u.id == userId).FirstOrDefault();<br>            <span class="hljs-keyword">return</span> user;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> User? GetCurrentUser()<br>        &#123;<br>            <span class="hljs-keyword">var</span> context = _httpContextAccessor.HttpContext;<br>            <span class="hljs-keyword">if</span> (context != <span class="hljs-literal">null</span> &amp;&amp; context.Items.ContainsKey(<span class="hljs-string">&quot;User&quot;</span>))<br>            &#123;<br>                <span class="hljs-keyword">return</span> (User?)context.Items[<span class="hljs-string">&quot;User&quot;</span>];<br>            &#125;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> <span class="hljs-title">GetExpiresMinutes</span>()</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> Convert.ToInt32(_configuration[<span class="hljs-string">&quot;JwtSettings:ExpirationMinutes&quot;</span>]);<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h4 id="5-3-新增过滤器全局验证-Token"><a href="#5-3-新增过滤器全局验证-Token" class="headerlink" title="5.3 新增过滤器全局验证 Token"></a>5.3 新增过滤器全局验证 Token</h4><p>只有标注 <code>[AllowAnonymous]</code> 特性的方法或者类才会跳过 Token 验证</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Loquy.Common.Dtos.Base;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Authorization;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Http;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;<br><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc.Filters;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Loquy.Common.Authorization</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">JwtFilter</span> : <span class="hljs-title">IAuthorizationFilter</span><br>    &#123;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IJwtUtils _jwtUtils;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">JwtFilter</span>(<span class="hljs-params">IJwtUtils jwtUtils</span>)</span><br>        &#123;<br>            _jwtUtils = jwtUtils;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnAuthorization</span>(<span class="hljs-params">AuthorizationFilterContext context</span>)</span><br>        &#123;<br>            <span class="hljs-comment">// 如果动作带有[AllowAnonymous]属性，则跳过授权</span><br>            <span class="hljs-keyword">var</span> allowAnonymous = context.ActionDescriptor.EndpointMetadata.OfType&lt;AllowAnonymousAttribute&gt;().Any();<br>            <span class="hljs-keyword">if</span> (allowAnonymous)<br>                <span class="hljs-keyword">return</span>;<br><br>            <span class="hljs-comment">// 授权</span><br>            <span class="hljs-keyword">var</span> token = context.HttpContext.Request.Headers[<span class="hljs-string">&quot;Authorization&quot;</span>].FirstOrDefault()?.Split(<span class="hljs-string">&quot; &quot;</span>).Last();<br>            <span class="hljs-keyword">var</span> userId = _jwtUtils.ValidateJwtToken(token);<br>            <span class="hljs-keyword">if</span> (userId == <span class="hljs-literal">null</span>)<br>            &#123;<br>                <span class="hljs-comment">// 用户未登录或token不正确</span><br>                <span class="hljs-keyword">var</span> resultModel = ResultModel&lt;<span class="hljs-built_in">string</span>&gt;.Fail(<span class="hljs-string">&quot;用户未登录或token不正确&quot;</span>);<br>                context.Result = <span class="hljs-keyword">new</span> JsonResult(resultModel) &#123; StatusCode = StatusCodes.Status401Unauthorized &#125;;<br>            &#125;<br>            <span class="hljs-keyword">else</span><br>            &#123;<br>                context.HttpContext.Items[<span class="hljs-string">&quot;User&quot;</span>] = _jwtUtils.GetUserByToken();<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h4 id="5-4-把-JWT-工具类和过滤器增加至项目启动文件"><a href="#5-4-把-JWT-工具类和过滤器增加至项目启动文件" class="headerlink" title="5.4 把 JWT 工具类和过滤器增加至项目启动文件"></a>5.4 把 JWT 工具类和过滤器增加至项目启动文件</h4><p>在 <code>Startup</code> 中的 <code>ConfigureServices</code> 方法中添加以下配置：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs csharp">Services.AddAuthentication(options =&gt;<br>&#123;<br>    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;<br>    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;<br>&#125;)<br>.AddJwtBearer(options =&gt;<br>&#123;<br>    options.TokenValidationParameters = <span class="hljs-keyword">new</span> TokenValidationParameters<br>    &#123;<br>        SaveSigninToken = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 保存 token,后台验证 token 是否生效(重要)</span><br>        ValidateIssuer = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 是否验证 Issuer</span><br>        ValidateAudience = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 是否验证 Audience</span><br>        ValidateLifetime = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 是否验证失效时间</span><br>        ValidateIssuerSigningKey = <span class="hljs-literal">true</span>, <span class="hljs-comment">// 是否验证 SecurityKey</span><br>        ValidAudience = AppSetting.Secret.Audience, <span class="hljs-comment">// Audience</span><br>        ValidIssuer = AppSetting.Secret.Issuer, <span class="hljs-comment">// Issuer，这两项和前面签发j wt 的设置一致</span><br>        IssuerSigningKey = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSetting.Secret.JWT))<br>    &#125;;<br>    options.Events = <span class="hljs-keyword">new</span> JwtBearerEvents()<br>    &#123;<br>        OnChallenge = context =&gt;<br>        &#123;<br>            context.HandleResponse();<br>            context.Response.Clear();<br>            context.Response.ContentType = <span class="hljs-string">&quot;application/json&quot;</span>;<br>            context.Response.StatusCode = StatusCodes.Status401Unauthorized;<br>            context.Response.WriteAsync(ResultModel&lt;<span class="hljs-built_in">string</span>&gt;.Fail(StatusCodes.Status401Unauthorized, <span class="hljs-string">&quot;授权未通过&quot;</span>).Serialize());<br>            <span class="hljs-keyword">return</span> Task.CompletedTask;<br>        &#125;<br>    &#125;;<br>&#125;);<br><br><span class="hljs-comment">// 注入 JWT</span><br>services.AddScoped&lt;IJwtUtils, JwtUtils&gt;();<br></code></pre></td></tr></table></figure><h4 id="5-5-前端封装通用的-HTTP-请求方法（Vue3-TS-Axios-Element-Plus）"><a href="#5-5-前端封装通用的-HTTP-请求方法（Vue3-TS-Axios-Element-Plus）" class="headerlink" title="5.5 前端封装通用的 HTTP 请求方法（Vue3 + TS + Axios + Element Plus）"></a>5.5 前端封装通用的 HTTP 请求方法（Vue3 + TS + Axios + Element Plus）</h4><p>前端 Token 处理：请求发起时拦截判断 <code>localStorage</code> 是否有 Token 然后添加到请求头，请求响应时拦截判断是否 401 授权失败则跳转登录页。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;axios&#x27;</span><br><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> &#123; <span class="hljs-title class_">AxiosInstance</span>, <span class="hljs-title class_">AxiosResponse</span>, <span class="hljs-title class_">AxiosRequestConfig</span> &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;axios&#x27;</span><br><span class="hljs-keyword">import</span> &#123; <span class="hljs-title class_">ElMessage</span>, <span class="hljs-title class_">ElLoading</span> &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;element-plus&#x27;</span><br><span class="hljs-keyword">import</span> router <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;@/router/index&quot;</span>;<br><br><span class="hljs-comment">// 创建一个 axios 实例，并设置基本 URL</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> <span class="hljs-attr">api</span>: <span class="hljs-title class_">AxiosInstance</span> = axios.<span class="hljs-title function_">create</span>(&#123;<br>  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">&#x27;http://localhost:8002/&#x27;</span>,<br>  <span class="hljs-attr">timeout</span>: <span class="hljs-number">10000</span> * <span class="hljs-number">6</span>, <span class="hljs-comment">// 设置超时时间为 60 秒</span><br>  <span class="hljs-attr">headers</span>: &#123;<br>    <span class="hljs-string">&#x27;Content-Type&#x27;</span>: <span class="hljs-string">&#x27;application/json&#x27;</span> <span class="hljs-comment">// 设置请求头为 JSON 格式</span><br>  &#125;<br>&#125;)<br><br><span class="hljs-comment">// 添加请求拦截器</span><br>api.<span class="hljs-property">interceptors</span>.<span class="hljs-property">request</span>.<span class="hljs-title function_">use</span>(<br>  <span class="hljs-function">(<span class="hljs-params">config</span>) =&gt;</span> &#123;<br>    <span class="hljs-keyword">const</span> token = <span class="hljs-variable language_">localStorage</span>.<span class="hljs-title function_">getItem</span>(<span class="hljs-string">&#x27;accessToken&#x27;</span>);<br>    <span class="hljs-keyword">if</span> (token) &#123;<br>      config.<span class="hljs-property">headers</span>.<span class="hljs-property">Authorization</span> = <span class="hljs-string">`Bearer <span class="hljs-subst">$&#123;token&#125;</span>`</span>;<br>    &#125;<br>    <span class="hljs-keyword">return</span> config<br>  &#125;,<br>  <span class="hljs-function">(<span class="hljs-params">error: <span class="hljs-built_in">any</span></span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 对请求错误做些什么</span><br>    <span class="hljs-keyword">return</span> <span class="hljs-title class_">Promise</span>.<span class="hljs-title function_">reject</span>(error)<br>  &#125;<br>)<br><br><span class="hljs-comment">// 添加响应拦截器</span><br>api.<span class="hljs-property">interceptors</span>.<span class="hljs-property">response</span>.<span class="hljs-title function_">use</span>(<br>  <span class="hljs-function">(<span class="hljs-params">response: AxiosResponse&lt;<span class="hljs-built_in">any</span>&gt;</span>) =&gt;</span> &#123;<br>    <span class="hljs-keyword">return</span> response<br>  &#125;,<br>  <span class="hljs-function">(<span class="hljs-params">error: <span class="hljs-built_in">any</span></span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 对响应错误做些什么</span><br>    <span class="hljs-keyword">if</span> (error.<span class="hljs-property">response</span> &amp;&amp; error.<span class="hljs-property">response</span>.<span class="hljs-property">status</span> === <span class="hljs-number">401</span>) &#123;<br>      <span class="hljs-title class_">ElMessage</span>.<span class="hljs-title function_">error</span>(error.<span class="hljs-property">response</span>.<span class="hljs-property">data</span>.<span class="hljs-property">message</span>)<br>      <span class="hljs-variable language_">localStorage</span>.<span class="hljs-title function_">removeItem</span>(<span class="hljs-string">&#x27;accessToken&#x27;</span>);<br>      router.<span class="hljs-title function_">push</span>(<span class="hljs-string">&#x27;/login&#x27;</span>); <br>    &#125;<br>    <span class="hljs-keyword">return</span> <span class="hljs-title class_">Promise</span>.<span class="hljs-title function_">reject</span>(error)<br>  &#125;<br>)<br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> request = (<br>  <span class="hljs-attr">url</span>: <span class="hljs-built_in">string</span>,<br>  <span class="hljs-attr">method</span>: <span class="hljs-string">&#x27;GET&#x27;</span> | <span class="hljs-string">&#x27;POST&#x27;</span> | <span class="hljs-string">&#x27;PUT&#x27;</span> | <span class="hljs-string">&#x27;DELETE&#x27;</span>,<br>  <span class="hljs-attr">params</span>: <span class="hljs-built_in">any</span> = &#123;&#125;,<br>  <span class="hljs-attr">loadingOptions</span>: <span class="hljs-built_in">any</span> = &#123;&#125;<br>): <span class="hljs-title class_">Promise</span>&lt;<span class="hljs-built_in">any</span>&gt; =&gt; &#123;<br>  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> &#123;<br>    <span class="hljs-keyword">const</span> defaultLoadingOptions = &#123;<br>      <span class="hljs-attr">lock</span>: <span class="hljs-literal">true</span>,<br>      <span class="hljs-attr">text</span>: <span class="hljs-string">&#x27;正在请求接口，请耐心等待&#x27;</span>,<br>      <span class="hljs-attr">background</span>: <span class="hljs-string">&#x27;rgba(0, 0, 0, 0.1)&#x27;</span><br>    &#125;<br><br>    <span class="hljs-keyword">let</span> <span class="hljs-attr">loading</span>: <span class="hljs-built_in">any</span><br>    <span class="hljs-keyword">if</span> (loadingOptions) &#123;<br>      <span class="hljs-keyword">const</span> finalLoadingOptions = &#123; ...defaultLoadingOptions, ...loadingOptions &#125;<br>      loading = <span class="hljs-title class_">ElLoading</span>.<span class="hljs-title function_">service</span>(finalLoadingOptions)<br>    &#125;<br><br>    <span class="hljs-keyword">const</span> <span class="hljs-attr">requestConfig</span>: <span class="hljs-title class_">AxiosRequestConfig</span> = &#123;<br>      url,<br>      method,<br>      <span class="hljs-attr">params</span>: method === <span class="hljs-string">&#x27;GET&#x27;</span> || method === <span class="hljs-string">&#x27;DELETE&#x27;</span> ? params : <span class="hljs-literal">null</span>,<br>      <span class="hljs-attr">data</span>: method === <span class="hljs-string">&#x27;POST&#x27;</span> || method === <span class="hljs-string">&#x27;PUT&#x27;</span> ? params : <span class="hljs-literal">null</span><br>    &#125;<br><br>    api<br>      .<span class="hljs-title function_">request</span>(requestConfig)<br>      .<span class="hljs-title function_">then</span>(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> &#123;<br>        <span class="hljs-keyword">const</span> result = response.<span class="hljs-property">data</span><br>        <span class="hljs-keyword">if</span> (result.<span class="hljs-property">code</span> === <span class="hljs-number">0</span>) &#123;<br>          <span class="hljs-title function_">resolve</span>(result)<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>          <span class="hljs-title class_">ElMessage</span>.<span class="hljs-title function_">error</span>(result)<br>          <span class="hljs-title function_">reject</span>(result)<br>        &#125;<br>      &#125;)<br>      .<span class="hljs-title function_">catch</span>(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> &#123;<br>        <span class="hljs-title class_">ElMessage</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">&#x27;接口发生错误：&#x27;</span> + error)<br>        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">&#x27;接口发生错误:&#x27;</span>, error)<br>        <span class="hljs-title function_">reject</span>(error)<br>      &#125;)<br>      .<span class="hljs-title function_">finally</span>(<span class="hljs-function">() =&gt;</span> &#123;<br>        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> &#123;<br>          loading?.<span class="hljs-title function_">close</span>()<br>        &#125;, <span class="hljs-number">500</span>)<br>      &#125;)<br>  &#125;)<br>&#125;<br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> api<br><br></code></pre></td></tr></table></figure>]]></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;在 ASP.NET Core 应用程序中，启动过程由主机（Host）负责，它负责配置应用程序并启动运行时环境</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
    <category term="ASP.NET Core" scheme="http://www.loquy.cn/tags/ASP-NET-Core/"/>
    
    <category term="Entity Framework Core" scheme="http://www.loquy.cn/tags/Entity-Framework-Core/"/>
    
    <category term="Swagger" scheme="http://www.loquy.cn/tags/Swagger/"/>
    
    <category term="FluentValidation" scheme="http://www.loquy.cn/tags/FluentValidation/"/>
    
    <category term="AutoMapper" scheme="http://www.loquy.cn/tags/AutoMapper/"/>
    
    <category term="Dependency injection" scheme="http://www.loquy.cn/tags/Dependency-injection/"/>
    
    <category term="NLog" scheme="http://www.loquy.cn/tags/NLog/"/>
    
    <category term="JWTBearer" scheme="http://www.loquy.cn/tags/JWTBearer/"/>
    
  </entry>
  
  <entry>
    <title>ADO.NET 使用教程</title>
    <link href="http://www.loquy.cn/posts/2a04719d.html"/>
    <id>http://www.loquy.cn/posts/2a04719d.html</id>
    <published>2023-12-22T06:58:38.000Z</published>
    <updated>2023-12-22T06:58:38.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-引言"><a href="#1-引言" class="headerlink" title="1. 引言"></a>1. 引言</h2><h3 id="1-1-ADO-NET简介"><a href="#1-1-ADO-NET简介" class="headerlink" title="1.1 ADO.NET简介"></a>1.1 ADO.NET简介</h3><h4 id="1-1-1-ADO-NET是什么？"><a href="#1-1-1-ADO-NET是什么？" class="headerlink" title="1.1.1 ADO.NET是什么？"></a>1.1.1 ADO.NET是什么？</h4><p>ADO.NET（ActiveX Data Objects for .NET）是Microsoft.NET平台上用于数据访问和操作的一组技术。它提供了一种灵活而强大的框架，使开发人员能够连接各种数据源，执行查询、更新和其他数据库操作。</p><h4 id="1-1-2-为什么使用ADO-NET？"><a href="#1-1-2-为什么使用ADO-NET？" class="headerlink" title="1.1.2 为什么使用ADO.NET？"></a>1.1.2 为什么使用ADO.NET？</h4><p>ADO.NET的设计旨在满足数据访问的多样性和复杂性。通过分离数据访问和数据表示，支持多种数据源，以及提供高性能的数据访问机制，ADO.NET为.NET应用程序提供了强大而可扩展的数据管理工具。</p><h3 id="1-2-ADO-NET的核心组件"><a href="#1-2-ADO-NET的核心组件" class="headerlink" title="1.2 ADO.NET的核心组件"></a>1.2 ADO.NET的核心组件</h3><h4 id="1-2-1-连接（Connection）"><a href="#1-2-1-连接（Connection）" class="headerlink" title="1.2.1 连接（Connection）"></a>1.2.1 连接（Connection）</h4><p>连接是与数据源建立通信的关键组件。ADO.NET提供了连接对象，允许应用程序建立到数据库的连接，以便执行后续的数据操作。</p><h4 id="1-2-2-命令（Command）"><a href="#1-2-2-命令（Command）" class="headerlink" title="1.2.2 命令（Command）"></a>1.2.2 命令（Command）</h4><p>命令对象允许应用程序定义并执行SQL命令。通过命令对象，可以执行查询、更新、插入和删除等数据库操作。</p><h4 id="1-2-3-数据读取器（DataReader）"><a href="#1-2-3-数据读取器（DataReader）" class="headerlink" title="1.2.3 数据读取器（DataReader）"></a>1.2.3 数据读取器（DataReader）</h4><p>数据读取器提供了一种只进的、高性能的读取数据的方式。它以流的形式逐行检索数据，适用于大型数据集的快速读取。</p><h4 id="1-2-4-数据适配器（DataAdapter）"><a href="#1-2-4-数据适配器（DataAdapter）" class="headerlink" title="1.2.4 数据适配器（DataAdapter）"></a>1.2.4 数据适配器（DataAdapter）</h4><p>数据适配器用于填充数据集（DataSet）并更新数据库。它充当数据源和数据集之间的桥梁，支持将数据在内存中进行操作和缓存。</p><p>在接下来的章节中，我们将深入探讨每个核心组件的使用方法，以及如何利用它们来实现灵活、高效的数据访问。</p><h1 id="2-连接数据库"><a href="#2-连接数据库" class="headerlink" title="2. 连接数据库"></a>2. 连接数据库</h1><h2 id="2-1-数据库连接字符串"><a href="#2-1-数据库连接字符串" class="headerlink" title="2.1 数据库连接字符串"></a>2.1 数据库连接字符串</h2><h3 id="2-1-1-常见连接字符串示例"><a href="#2-1-1-常见连接字符串示例" class="headerlink" title="2.1.1 常见连接字符串示例"></a>2.1.1 常见连接字符串示例</h3><p>数据库连接字符串是连接到数据库时的关键配置信息。不同数据库系统有不同的连接字符串格式，以下是一些常见数据库的连接字符串示例：</p><h4 id="2-1-1-1-SQL-Server连接字符串"><a href="#2-1-1-1-SQL-Server连接字符串" class="headerlink" title="2.1.1.1 SQL Server连接字符串"></a>2.1.1.1 SQL Server连接字符串</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;<br></code></pre></td></tr></table></figure><h4 id="2-1-1-2-MySQL连接字符串"><a href="#2-1-1-2-MySQL连接字符串" class="headerlink" title="2.1.1.2 MySQL连接字符串"></a>2.1.1.2 MySQL连接字符串</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;<br></code></pre></td></tr></table></figure><h4 id="2-1-1-3-Oracle连接字符串"><a href="#2-1-1-3-Oracle连接字符串" class="headerlink" title="2.1.1.3 Oracle连接字符串"></a>2.1.1.3 Oracle连接字符串</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">Data Source=myOracleDB;User Id=myUsername;Password=myPassword;<br></code></pre></td></tr></table></figure><h3 id="2-1-2-连接字符串中的重要参数"><a href="#2-1-2-连接字符串中的重要参数" class="headerlink" title="2.1.2 连接字符串中的重要参数"></a>2.1.2 连接字符串中的重要参数</h3><p>连接字符串中包含各种参数，以下是一些常见的参数及其作用：</p><h4 id="2-1-2-1-Data-Source（或-Server）"><a href="#2-1-2-1-Data-Source（或-Server）" class="headerlink" title="2.1.2.1 Data Source（或 Server）"></a>2.1.2.1 Data Source（或 Server）</h4><p>指定数据库服务器的地址或名称。</p><h4 id="2-1-2-2-Initial-Catalog（或-Database）"><a href="#2-1-2-2-Initial-Catalog（或-Database）" class="headerlink" title="2.1.2.2 Initial Catalog（或 Database）"></a>2.1.2.2 Initial Catalog（或 Database）</h4><p>指定要连接的数据库的名称。</p><h4 id="2-1-2-3-User-Id（或-Uid）和-Password（或-Pwd）"><a href="#2-1-2-3-User-Id（或-Uid）和-Password（或-Pwd）" class="headerlink" title="2.1.2.3 User Id（或 Uid）和 Password（或 Pwd）"></a>2.1.2.3 User Id（或 Uid）和 Password（或 Pwd）</h4><p>指定连接数据库所使用的用户名和密码。</p><h2 id="2-1-建立数据库连接"><a href="#2-1-建立数据库连接" class="headerlink" title="2.1. 建立数据库连接"></a>2.1. 建立数据库连接</h2><h3 id="2-1-1-使用SqlConnection类"><a href="#2-1-1-使用SqlConnection类" class="headerlink" title="2.1.1 使用SqlConnection类"></a>2.1.1 使用SqlConnection类</h3><p>在.NET中，可以使用<code>SqlConnection</code>类来建立与SQL Server数据库的连接。以下是一个简单的连接示例：</p><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs cs"><span class="hljs-built_in">string</span> connectionString = <span class="hljs-string">&quot;Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br>    <span class="hljs-comment">// 在此执行数据库操作</span><br>&#125;<br></code></pre></td></tr></table></figure><h3 id="2-1-2-打开和关闭连接"><a href="#2-1-2-打开和关闭连接" class="headerlink" title="2.1.2 打开和关闭连接"></a>2.1.2 打开和关闭连接</h3><p>连接成功后，务必在不再需要连接时将其关闭，以释放资源。使用<code>Open</code>方法打开连接，使用<code>Close</code>方法关闭连接：</p><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cs">connection.Open(); <span class="hljs-comment">// 打开连接</span><br><span class="hljs-comment">// 执行数据库操作</span><br>connection.Close(); <span class="hljs-comment">// 关闭连接</span><br></code></pre></td></tr></table></figure><p>通过以上介绍，读者现在应该了解到如何构建数据库连接字符串以及如何使用<code>SqlConnection</code>类来建立和关闭数据库连接。在下一章节中，我们将深入研究执行SQL命令的方式，包括使用<code>SqlCommand</code>对象和参数化查询。</p><h1 id="3-执行SQL命令"><a href="#3-执行SQL命令" class="headerlink" title="3. 执行SQL命令"></a>3. 执行SQL命令</h1><h2 id="3-1-创建SqlCommand对象"><a href="#3-1-创建SqlCommand对象" class="headerlink" title="3.1  创建SqlCommand对象"></a>3.1  创建SqlCommand对象</h2><h3 id="3-1-1-常见构造方法"><a href="#3-1-1-常见构造方法" class="headerlink" title="3.1.1 常见构造方法"></a>3.1.1 常见构造方法</h3><p><code>SqlCommand</code>是执行与SQL Server数据库交互的关键类。以下是一些创建<code>SqlCommand</code>对象的常见方式：</p><h4 id="3-1-1-1-基本构造方法"><a href="#3-1-1-1-基本构造方法" class="headerlink" title="3.1.1.1 基本构造方法"></a>3.1.1.1 基本构造方法</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand();<br></code></pre></td></tr></table></figure><h4 id="3-1-1-2-指定SQL语句和连接的构造方法"><a href="#3-1-1-2-指定SQL语句和连接的构造方法" class="headerlink" title="3.1.1.2 指定SQL语句和连接的构造方法"></a>3.1.1.2 指定SQL语句和连接的构造方法</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT * FROM TableName&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-1-2-参数化查询"><a href="#3-1-2-参数化查询" class="headerlink" title="3.1.2 参数化查询"></a>3.1.2 参数化查询</h3><p>参数化查询是一种防止SQL注入攻击的重要方式。通过使用参数，可以安全地将用户输入嵌入到SQL命令中。以下是参数化查询的示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT * FROM TableName WHERE ColumnName = @param1&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@param1&quot;</span>, userValue);<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="3-2-执行SQL命令"><a href="#3-2-执行SQL命令" class="headerlink" title="3.2 执行SQL命令"></a>3.2 执行SQL命令</h2><h3 id="3-2-1-ExecuteNonQuery方法"><a href="#3-2-1-ExecuteNonQuery方法" class="headerlink" title="3.2.1 ExecuteNonQuery方法"></a>3.2.1 ExecuteNonQuery方法</h3><p><code>ExecuteNonQuery</code>方法用于执行不返回结果集的SQL语句，如INSERT、UPDATE和DELETE。示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;INSERT INTO TableName (ColumnName) VALUES (@param1)&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@param1&quot;</span>, userValue);<br>    <br>    connection.Open();<br>    <span class="hljs-built_in">int</span> rowsAffected = command.ExecuteNonQuery();<br>    connection.Close();<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-2-2-ExecuteScalar方法"><a href="#3-2-2-ExecuteScalar方法" class="headerlink" title="3.2.2 ExecuteScalar方法"></a>3.2.2 ExecuteScalar方法</h3><p><code>ExecuteScalar</code>方法用于执行查询并返回结果集的第一行第一列。通常用于获取聚合函数的结果或查询单一值。示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT COUNT(*) FROM TableName&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br><br>    connection.Open();<br>    <span class="hljs-built_in">object</span> result = command.ExecuteScalar();<br>    connection.Close();<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-2-3-ExecuteReader方法"><a href="#3-2-3-ExecuteReader方法" class="headerlink" title="3.2.3 ExecuteReader方法"></a>3.2.3 ExecuteReader方法</h3><p><code>ExecuteReader</code>方法用于执行查询并返回<code>SqlDataReader</code>对象，用于逐行读取查询结果。示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT * FROM TableName&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br><br>    connection.Open();<br>    <span class="hljs-keyword">using</span> (SqlDataReader reader = command.ExecuteReader())<br>    &#123;<br>        <span class="hljs-keyword">while</span> (reader.Read())<br>        &#123;<br>            <span class="hljs-comment">// 处理每一行数据</span><br>        &#125;<br>    &#125;<br>    connection.Close();<br>&#125;<br></code></pre></td></tr></table></figure><p>通过以上介绍，读者应该了解如何创建<code>SqlCommand</code>对象，执行不同类型的SQL命令，并且学会了如何使用参数化查询提高应用程序的安全性。在下一章节中，我们将深入研究数据的读取和处理，包括使用<code>DataReader</code>逐行读取数据。</p><h1 id="4-数据读取和处理"><a href="#4-数据读取和处理" class="headerlink" title="4. 数据读取和处理"></a>4. 数据读取和处理</h1><h2 id="4-1-使用DataReader读取数据"><a href="#4-1-使用DataReader读取数据" class="headerlink" title="4.1 使用DataReader读取数据"></a>4.1 使用DataReader读取数据</h2><h3 id="4-1-1-逐行读取数据"><a href="#4-1-1-逐行读取数据" class="headerlink" title="4.1.1 逐行读取数据"></a>4.1.1 逐行读取数据</h3><p><code>DataReader</code>提供了一种高效的逐行读取数据的方式，适用于大量数据的快速检索。以下是一个基本的使用示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT * FROM TableName&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br><br>    connection.Open();<br>    <span class="hljs-keyword">using</span> (SqlDataReader reader = command.ExecuteReader())<br>    &#123;<br>        <span class="hljs-keyword">while</span> (reader.Read())<br>        &#123;<br>            <span class="hljs-comment">// 读取每一行数据</span><br>            <span class="hljs-built_in">int</span> column1Value = reader.GetInt32(<span class="hljs-number">0</span>); <span class="hljs-comment">// 通过列索引获取值</span><br>            <span class="hljs-built_in">string</span> column2Value = reader.GetString(<span class="hljs-number">1</span>); <span class="hljs-comment">// 通过列索引获取值</span><br>            <span class="hljs-comment">// 处理数据...</span><br>        &#125;<br>    &#125;<br>    connection.Close();<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="4-1-2-获取列数据"><a href="#4-1-2-获取列数据" class="headerlink" title="4.1.2 获取列数据"></a>4.1.2 获取列数据</h3><p><code>DataReader</code>提供了多种方法用于获取不同数据类型的列值。以下是一些常见的获取列数据的方法：</p><ul><li><code>GetInt32(int ordinal)</code>：获取整数类型列的值。</li><li><code>GetString(int ordinal)</code>：获取字符串类型列的值。</li><li><code>GetDateTime(int ordinal)</code>：获取日期时间类型列的值。</li><li>其他类型的获取方法，如<code>GetBoolean</code>、<code>GetDecimal</code>等。</li></ul><h2 id="4-2-数据类型映射"><a href="#4-2-数据类型映射" class="headerlink" title="4.2 数据类型映射"></a>4.2 数据类型映射</h2><h3 id="4-2-1-ADO-NET数据类型"><a href="#4-2-1-ADO-NET数据类型" class="headerlink" title="4.2.1 ADO.NET数据类型"></a>4.2.1 ADO.NET数据类型</h3><p>ADO.NET支持与数据库中的多种数据类型进行映射。以下是一些常见的ADO.NET数据类型：</p><ul><li><code>Int32</code>：整数类型</li><li><code>String</code>：字符串类型</li><li><code>DateTime</code>：日期时间类型</li><li><code>Boolean</code>：布尔类型</li><li><code>Decimal</code>：十进制类型</li><li>…</li></ul><h3 id="4-2-2-数据库数据类型"><a href="#4-2-2-数据库数据类型" class="headerlink" title="4.2.2 数据库数据类型"></a>4.2.2 数据库数据类型</h3><p>不同的数据库系统支持不同的数据类型，因此在读取数据时，需要确保数据类型的正确映射。例如，SQL Server中的<code>int</code>类型对应于C#中的<code>Int32</code>类型，而MySQL中的<code>INT</code>类型也对应于C#中的<code>Int32</code>类型。</p><p>通过<code>DataReader</code>逐行读取数据，并理解数据类型的映射关系，开发人员可以灵活处理不同类型的数据，并确保应用程序对数据的正确解释和使用。</p><p>在下一章节中，我们将介绍数据适配器和数据集的概念，以及如何使用它们进行离线数据处理和缓存。</p><h1 id="5-数据适配器和数据集"><a href="#5-数据适配器和数据集" class="headerlink" title="5. 数据适配器和数据集"></a>5. 数据适配器和数据集</h1><h2 id="5-1-数据适配器的作用"><a href="#5-1-数据适配器的作用" class="headerlink" title="5.1 数据适配器的作用"></a>5.1 数据适配器的作用</h2><p>数据适配器是ADO.NET中的关键组件之一，用于在数据源（如数据库）和数据集之间建立桥梁。它负责将数据源中的数据填充到数据集中，以及将数据集中的更改提交回数据源。</p><h3 id="5-1-1-数据适配器的基本用法"><a href="#5-1-1-数据适配器的基本用法" class="headerlink" title="5.1.1 数据适配器的基本用法"></a>5.1.1 数据适配器的基本用法</h3><p>数据适配器通过执行命令（如SELECT、INSERT、UPDATE、DELETE）来与数据库进行交互，将数据填充到数据集中，并通过数据集将修改反馈给数据库。以下是数据适配器的基本用法：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT * FROM TableName&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlDataAdapter adapter = <span class="hljs-keyword">new</span> SqlDataAdapter(queryString, connection);<br><br>    DataSet dataSet = <span class="hljs-keyword">new</span> DataSet();<br>    <br>    <span class="hljs-comment">// 使用数据适配器填充数据集</span><br>    adapter.Fill(dataSet, <span class="hljs-string">&quot;TableName&quot;</span>);<br><br>    <span class="hljs-comment">// 对数据集进行操作...</span><br><br>    <span class="hljs-comment">// 提交更改到数据库</span><br>    adapter.Update(dataSet, <span class="hljs-string">&quot;TableName&quot;</span>);<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="5-2-使用DataSet和DataTable"><a href="#5-2-使用DataSet和DataTable" class="headerlink" title="5.2 使用DataSet和DataTable"></a>5.2 使用DataSet和DataTable</h2><h3 id="5-2-1-创建DataSet和DataTable对象"><a href="#5-2-1-创建DataSet和DataTable对象" class="headerlink" title="5.2.1 创建DataSet和DataTable对象"></a>5.2.1 创建DataSet和DataTable对象</h3><p>在使用数据集和数据表之前，需要创建相应的对象。以下是创建<code>DataSet</code>和<code>DataTable</code>对象的示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp">DataSet dataSet = <span class="hljs-keyword">new</span> DataSet(<span class="hljs-string">&quot;MyDataSet&quot;</span>);<br><br><span class="hljs-comment">// 创建DataTable</span><br>DataTable dataTable = <span class="hljs-keyword">new</span> DataTable(<span class="hljs-string">&quot;MyDataTable&quot;</span>);<br><br><span class="hljs-comment">// 将DataTable添加到DataSet中</span><br>dataSet.Tables.Add(dataTable);<br></code></pre></td></tr></table></figure><h3 id="5-2-2-数据关系和约束"><a href="#5-2-2-数据关系和约束" class="headerlink" title="5.2.2 数据关系和约束"></a>5.2.2 数据关系和约束</h3><p>数据集支持数据表之间的关系和约束，以维护数据的完整性。</p><h4 id="5-2-2-1-创建数据关系"><a href="#5-2-2-1-创建数据关系" class="headerlink" title="5.2.2.1 创建数据关系"></a>5.2.2.1 创建数据关系</h4><p>数据关系定义了不同数据表之间的关联，方便在应用程序中进行更复杂的查询和操作。以下是创建数据关系的示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs csharp">DataRelation relation = <span class="hljs-keyword">new</span> DataRelation(<span class="hljs-string">&quot;MyRelation&quot;</span>, parentTable.Columns[<span class="hljs-string">&quot;ParentColumn&quot;</span>], childTable.Columns[<span class="hljs-string">&quot;ChildColumn&quot;</span>]);<br>dataSet.Relations.Add(relation);<br></code></pre></td></tr></table></figure><h4 id="5-2-2-2-添加约束"><a href="#5-2-2-2-添加约束" class="headerlink" title="5.2.2.2 添加约束"></a>5.2.2.2 添加约束</h4><p>约束用于定义数据表中列的规则，确保数据的正确性和完整性。以下是添加约束的示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs csharp">UniqueConstraint uniqueConstraint = <span class="hljs-keyword">new</span> UniqueConstraint(dataTable.Columns[<span class="hljs-string">&quot;ColumnName&quot;</span>]);<br>dataTable.Constraints.Add(uniqueConstraint);<br></code></pre></td></tr></table></figure><p>通过以上介绍，读者应该了解了数据适配器的作用，以及如何使用<code>DataSet</code>和<code>DataTable</code>进行离线数据处理和数据关系、约束的操作。在下一章节中，我们将深入探讨数据库事务的概念和在ADO.NET中的实际应用。</p><h1 id="6-数据库事务"><a href="#6-数据库事务" class="headerlink" title="6. 数据库事务"></a>6. 数据库事务</h1><h2 id="6-1-事务的基本概念"><a href="#6-1-事务的基本概念" class="headerlink" title="6.1 事务的基本概念"></a>6.1 事务的基本概念</h2><h3 id="6-1-1-什么是事务？"><a href="#6-1-1-什么是事务？" class="headerlink" title="6.1.1 什么是事务？"></a>6.1.1 什么是事务？</h3><p>事务是数据库管理系统执行的一个操作序列，它要么完全执行，要么完全不执行，不会结束在中间的某个状态。事务可以包含一个或多个数据库操作，如插入、更新、删除等。</p><h3 id="6-1-2-事务的特性"><a href="#6-1-2-事务的特性" class="headerlink" title="6.1.2 事务的特性"></a>6.1.2 事务的特性</h3><p>事务具有以下四个特性，通常被称为ACID特性：</p><ul><li><p><strong>原子性（Atomicity）</strong>：事务中的所有操作要么全部完成，要么全部撤销。如果事务中的任何一个操作失败，整个事务将被回滚，所有的更改都不会生效。</p></li><li><p><strong>一致性（Consistency）</strong>：事务使数据库从一个一致性状态转移到另一个一致性状态。事务执行前后，数据库应保持一致性。</p></li><li><p><strong>隔离性（Isolation）</strong>：事务的执行不受其他事务的干扰。即使有其他事务在同时执行，一个事务的执行不应影响其他事务。</p></li><li><p><strong>持久性（Durability）</strong>：一旦事务完成，其结果就是永久性的。即使系统崩溃，数据库也应该能够在恢复后保持事务的结果。</p></li></ul><h2 id="6-2-ADO-NET中的事务处理"><a href="#6-2-ADO-NET中的事务处理" class="headerlink" title="6.2 ADO.NET中的事务处理"></a>6.2 ADO.NET中的事务处理</h2><h3 id="6-2-1-事务的开启和提交"><a href="#6-2-1-事务的开启和提交" class="headerlink" title="6.2.1 事务的开启和提交"></a>6.2.1 事务的开启和提交</h3><p>在ADO.NET中，可以使用<code>SqlTransaction</code>类来实现事务处理。以下是事务的开启和提交的基本用法：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br><br>    <span class="hljs-comment">// 开始事务</span><br>    SqlTransaction transaction = connection.BeginTransaction();<br><br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        <span class="hljs-comment">// 在事务中执行数据库操作</span><br>        SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;UPDATE TableName SET ColumnName = Value&quot;</span>, connection, transaction);<br>        command.ExecuteNonQuery();<br><br>        <span class="hljs-comment">// 提交事务</span><br>        transaction.Commit();<br>    &#125;<br>    <span class="hljs-keyword">catch</span> (Exception ex)<br>    &#123;<br>        <span class="hljs-comment">// 发生异常，回滚事务</span><br>        transaction.Rollback();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="6-2-2-事务的回滚"><a href="#6-2-2-事务的回滚" class="headerlink" title="6.2.2 事务的回滚"></a>6.2.2 事务的回滚</h3><p>如果在事务执行过程中发生异常或者事务操作不符合预期，可以通过回滚来撤销事务中的所有更改：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">transaction.Rollback();<br></code></pre></td></tr></table></figure><p>通过使用事务，可以确保数据库操作的一致性和完整性。在下一章节中，我们将介绍异常处理和错误处理的最佳实践，以确保应用程序在面临异常情况时能够做出适当的处理。</p><h1 id="7-异常处理和错误处理"><a href="#7-异常处理和错误处理" class="headerlink" title="7 异常处理和错误处理"></a>7 异常处理和错误处理</h1><h2 id="7-1-ADO-NET中的异常"><a href="#7-1-ADO-NET中的异常" class="headerlink" title="7.1 ADO.NET中的异常"></a>7.1 ADO.NET中的异常</h2><h3 id="7-1-1-常见的异常类型"><a href="#7-1-1-常见的异常类型" class="headerlink" title="7.1.1 常见的异常类型"></a>7.1.1 常见的异常类型</h3><p>在ADO.NET中，可能发生各种异常，例如数据库连接失败、SQL语法错误等。以下是一些常见的异常类型：</p><ul><li><code>SqlException</code>：与SQL Server相关的异常。</li><li><code>DbException</code>：通用数据库异常类型。</li><li><code>InvalidOperationException</code>：在无效操作时引发的异常。</li><li><code>ArgumentException</code>：参数无效时引发的异常。</li><li>其他与数据库操作相关的异常类型。</li></ul><h3 id="7-1-2-异常处理的最佳实践"><a href="#7-1-2-异常处理的最佳实践" class="headerlink" title="7.1.2 异常处理的最佳实践"></a>7.1.2 异常处理的最佳实践</h3><p>在处理异常时，建议使用适当的异常类型来捕获和处理异常。以下是一些最佳实践：</p><h4 id="7-1-2-1-使用多个catch块"><a href="#7-1-2-1-使用多个catch块" class="headerlink" title="7.1.2.1 使用多个catch块"></a>7.1.2.1 使用多个<code>catch</code>块</h4><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">try</span><br>&#123;<br>    <span class="hljs-comment">// 数据库操作...</span><br>&#125;<br><span class="hljs-keyword">catch</span> (SqlException ex)<br>&#123;<br>    <span class="hljs-comment">// 处理数据库相关的异常</span><br>    Console.WriteLine(<span class="hljs-string">$&quot;SQL Exception: <span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>&#125;<br><span class="hljs-keyword">catch</span> (DbException ex)<br>&#123;<br>    <span class="hljs-comment">// 处理通用数据库异常</span><br>    Console.WriteLine(<span class="hljs-string">$&quot;Database Exception: <span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>&#125;<br><span class="hljs-keyword">catch</span> (Exception ex)<br>&#123;<br>    <span class="hljs-comment">// 处理其他异常</span><br>    Console.WriteLine(<span class="hljs-string">$&quot;Exception: <span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>&#125;<br><span class="hljs-keyword">finally</span><br>&#123;<br>    <span class="hljs-comment">// 在这里执行清理工作，如关闭连接等</span><br>&#125;<br></code></pre></td></tr></table></figure><h4 id="7-1-2-2-使用finally块进行清理"><a href="#7-1-2-2-使用finally块进行清理" class="headerlink" title="7.1.2.2 使用finally块进行清理"></a>7.1.2.2 使用<code>finally</code>块进行清理</h4><p><code>finally</code>块中的代码总是会执行，无论是否发生异常。这里可以放置一些清理资源的代码，如关闭数据库连接。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">try</span><br>&#123;<br>    <span class="hljs-comment">// 数据库操作...</span><br>&#125;<br><span class="hljs-keyword">catch</span> (SqlException ex)<br>&#123;<br>    <span class="hljs-comment">// 处理数据库相关的异常</span><br>    Console.WriteLine(<span class="hljs-string">$&quot;SQL Exception: <span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>&#125;<br><span class="hljs-keyword">finally</span><br>&#123;<br>    <span class="hljs-comment">// 在这里执行清理工作，如关闭连接等</span><br>&#125;<br></code></pre></td></tr></table></figure><h4 id="7-1-2-3-使用using语句自动释放资源"><a href="#7-1-2-3-使用using语句自动释放资源" class="headerlink" title="7.1.2.3 使用using语句自动释放资源"></a>7.1.2.3 使用<code>using</code>语句自动释放资源</h4><p>对于需要手动释放的资源，可以使用<code>using</code>语句，确保资源在使用完毕后被正确释放。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        connection.Open();<br>        <span class="hljs-comment">// 数据库操作...</span><br>    &#125;<br>    <span class="hljs-keyword">catch</span> (SqlException ex)<br>    &#123;<br>        <span class="hljs-comment">// 处理数据库相关的异常</span><br>        Console.WriteLine(<span class="hljs-string">$&quot;SQL Exception: <span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>    &#125;<br>    <span class="hljs-comment">// 不需要显式关闭连接，using语句会自动调用connection.Dispose()</span><br>&#125;<br></code></pre></td></tr></table></figure><p>通过以上最佳实践，可以有效地处理异常，并确保应用程序在发生异常时能够保持稳定。在下一章节中，我们将介绍最佳实践和性能优化，以确保应用程序的高效运行。</p><h1 id="8-最佳实践和性能优化"><a href="#8-最佳实践和性能优化" class="headerlink" title="8. 最佳实践和性能优化"></a>8. 最佳实践和性能优化</h1><h2 id="8-1-参数化查询的重要性"><a href="#8-1-参数化查询的重要性" class="headerlink" title="8.1 参数化查询的重要性"></a>8.1 参数化查询的重要性</h2><h3 id="8-1-1-什么是参数化查询？"><a href="#8-1-1-什么是参数化查询？" class="headerlink" title="8.1.1 什么是参数化查询？"></a>8.1.1 什么是参数化查询？</h3><p>参数化查询是通过将参数传递给SQL查询，而不是直接将用户输入嵌入到查询字符串中，从而防止SQL注入攻击。参数化查询可以提高查询性能，并提高应用程序的安全性。</p><h3 id="8-1-2-参数化查询的示例"><a href="#8-1-2-参数化查询的示例" class="headerlink" title="8.1.2 参数化查询的示例"></a>8.1.2 参数化查询的示例</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> queryString = <span class="hljs-string">&quot;SELECT * FROM TableName WHERE ColumnName = @param1&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(queryString, connection);<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@param1&quot;</span>, userValue);<br><br>    connection.Open();<br>    <span class="hljs-keyword">using</span> (SqlDataReader reader = command.ExecuteReader())<br>    &#123;<br>        <span class="hljs-comment">// 处理查询结果...</span><br>    &#125;<br>    connection.Close();<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="8-2-数据库连接池"><a href="#8-2-数据库连接池" class="headerlink" title="8.2 数据库连接池"></a>8.2 数据库连接池</h2><h3 id="8-2-1-什么是数据库连接池？"><a href="#8-2-1-什么是数据库连接池？" class="headerlink" title="8.2.1 什么是数据库连接池？"></a>8.2.1 什么是数据库连接池？</h3><p>数据库连接池是一种维护和管理数据库连接的技术，它允许应用程序在需要时从连接池中获取连接，而不是每次都重新创建连接。连接池可以提高应用程序的性能和资源利用率。</p><h3 id="8-2-2-使用数据库连接池的示例"><a href="#8-2-2-使用数据库连接池的示例" class="headerlink" title="8.2.2 使用数据库连接池的示例"></a>8.2.2 使用数据库连接池的示例</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-comment">// 使用连接字符串创建连接，连接会自动添加到连接池</span><br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br>    <span class="hljs-comment">// 执行数据库操作...</span><br>&#125;<br><span class="hljs-comment">// 连接会被自动放回连接池</span><br></code></pre></td></tr></table></figure><h2 id="8-3-数据缓存和性能提升"><a href="#8-3-数据缓存和性能提升" class="headerlink" title="8.3 数据缓存和性能提升"></a>8.3 数据缓存和性能提升</h2><h3 id="8-3-1-什么是数据缓存？"><a href="#8-3-1-什么是数据缓存？" class="headerlink" title="8.3.1 什么是数据缓存？"></a>8.3.1 什么是数据缓存？</h3><p>数据缓存是将一部分数据存储在内存中，以提高对这些数据的访问速度。在某些情况下，缓存可以减少对数据库的频繁访问，提高应用程序性能。</p><h3 id="8-3-2-使用数据缓存的示例"><a href="#8-3-2-使用数据缓存的示例" class="headerlink" title="8.3.2 使用数据缓存的示例"></a>8.3.2 使用数据缓存的示例</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-comment">// 使用缓存库（如MemoryCache）存储数据</span><br>MemoryCache cache = <span class="hljs-keyword">new</span> MemoryCache(<span class="hljs-keyword">new</span> MemoryCacheOptions());<br>List&lt;DataItem&gt; data = <span class="hljs-literal">null</span>;<br><br><span class="hljs-comment">// 尝试从缓存中获取数据</span><br><span class="hljs-keyword">if</span> (!cache.TryGetValue(<span class="hljs-string">&quot;CachedData&quot;</span>, <span class="hljs-keyword">out</span> data))<br>&#123;<br>    <span class="hljs-comment">// 数据不在缓存中，从数据库中获取数据</span><br>    data = GetDataFromDatabase();<br><br>    <span class="hljs-comment">// 将数据存入缓存，设置过期时间等</span><br>    cache.Set(<span class="hljs-string">&quot;CachedData&quot;</span>, data, TimeSpan.FromMinutes(<span class="hljs-number">10</span>));<br>&#125;<br><br><span class="hljs-comment">// 使用数据...</span><br></code></pre></td></tr></table></figure><p>通过以上最佳实践和性能优化方法，可以提高应用程序的性能、安全性，并有效地管理数据库连接。这些方法有助于确保应用程序在处理大量数据时仍能保持高效。</p><h1 id="9-实例演练"><a href="#9-实例演练" class="headerlink" title="9. 实例演练"></a>9. 实例演练</h1><h2 id="9-1-基于ADO-NET的简单CRUD操作示例"><a href="#9-1-基于ADO-NET的简单CRUD操作示例" class="headerlink" title="9.1 基于ADO.NET的简单CRUD操作示例"></a>9.1 基于ADO.NET的简单CRUD操作示例</h2><h3 id="9-1-1-连接数据库"><a href="#9-1-1-连接数据库" class="headerlink" title="9.1.1 连接数据库"></a>9.1.1 连接数据库</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> connectionString = <span class="hljs-string">&quot;YourConnectionString&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br><br>    <span class="hljs-comment">// 执行CRUD操作...</span><br>    <br>    connection.Close();<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="9-1-2-插入数据"><a href="#9-1-2-插入数据" class="headerlink" title="9.1.2 插入数据"></a>9.1.2 插入数据</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> insertQuery = <span class="hljs-string">&quot;INSERT INTO TableName (Column1, Column2) VALUES (@Value1, @Value2)&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(insertQuery, connection))<br>&#123;<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@Value1&quot;</span>, value1);<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@Value2&quot;</span>, value2);<br><br>    <span class="hljs-built_in">int</span> rowsAffected = command.ExecuteNonQuery();<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="9-1-3-查询数据"><a href="#9-1-3-查询数据" class="headerlink" title="9.1.3 查询数据"></a>9.1.3 查询数据</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> selectQuery = <span class="hljs-string">&quot;SELECT * FROM TableName&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(selectQuery, connection))<br>&#123;<br>    <span class="hljs-keyword">using</span> (SqlDataReader reader = command.ExecuteReader())<br>    &#123;<br>        <span class="hljs-keyword">while</span> (reader.Read())<br>        &#123;<br>            <span class="hljs-comment">// 处理查询结果...</span><br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="9-1-4-更新数据"><a href="#9-1-4-更新数据" class="headerlink" title="9.1.4 更新数据"></a>9.1.4 更新数据</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> updateQuery = <span class="hljs-string">&quot;UPDATE TableName SET Column1 = @NewValue WHERE Column2 = @OldValue&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(updateQuery, connection))<br>&#123;<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@NewValue&quot;</span>, newValue);<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@OldValue&quot;</span>, oldValue);<br><br>    <span class="hljs-built_in">int</span> rowsAffected = command.ExecuteNonQuery();<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="9-1-5-删除数据"><a href="#9-1-5-删除数据" class="headerlink" title="9.1.5 删除数据"></a>9.1.5 删除数据</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-built_in">string</span> deleteQuery = <span class="hljs-string">&quot;DELETE FROM TableName WHERE Column = @Value&quot;</span>;<br><span class="hljs-keyword">using</span> (SqlCommand command = <span class="hljs-keyword">new</span> SqlCommand(deleteQuery, connection))<br>&#123;<br>    command.Parameters.AddWithValue(<span class="hljs-string">&quot;@Value&quot;</span>, <span class="hljs-keyword">value</span>);<br><br>    <span class="hljs-built_in">int</span> rowsAffected = command.ExecuteNonQuery();<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="10-2-数据库事务的实际应用"><a href="#10-2-数据库事务的实际应用" class="headerlink" title="10.2 数据库事务的实际应用"></a>10.2 数据库事务的实际应用</h2><h3 id="10-2-1-开启事务"><a href="#10-2-1-开启事务" class="headerlink" title="10.2.1 开启事务"></a>10.2.1 开启事务</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br><br>    <span class="hljs-comment">// 开始事务</span><br>    SqlTransaction transaction = connection.BeginTransaction();<br><br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        <span class="hljs-comment">// 执行数据库操作...</span><br><br>        <span class="hljs-comment">// 提交事务</span><br>        transaction.Commit();<br>    &#125;<br>    <span class="hljs-keyword">catch</span> (Exception ex)<br>    &#123;<br>        <span class="hljs-comment">// 发生异常，回滚事务</span><br>        transaction.Rollback();<br>    &#125;<br>    <span class="hljs-keyword">finally</span><br>    &#123;<br>        connection.Close();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="10-2-2-事务中的多个操作"><a href="#10-2-2-事务中的多个操作" class="headerlink" title="10.2.2 事务中的多个操作"></a>10.2.2 事务中的多个操作</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br><br>    <span class="hljs-comment">// 开始事务</span><br>    SqlTransaction transaction = connection.BeginTransaction();<br><br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        <span class="hljs-comment">// 执行数据库操作1</span><br>        SqlCommand command1 = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;UPDATE TableName SET Column1 = Value1&quot;</span>, connection, transaction);<br>        command1.ExecuteNonQuery();<br><br>        <span class="hljs-comment">// 执行数据库操作2</span><br>        SqlCommand command2 = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;UPDATE TableName SET Column2 = Value2&quot;</span>, connection, transaction);<br>        command2.ExecuteNonQuery();<br><br>        <span class="hljs-comment">// 提交事务</span><br>        transaction.Commit();<br>    &#125;<br>    <span class="hljs-keyword">catch</span> (Exception ex)<br>    &#123;<br>        <span class="hljs-comment">// 发生异常，回滚事务</span><br>        transaction.Rollback();<br>    &#125;<br>    <span class="hljs-keyword">finally</span><br>    &#123;<br>        connection.Close();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>通过以上实例演练，读者应该能够掌握基于ADO.NET进行简单CRUD操作的方法以及数据库事务的实际应用。这些实例有助于将理论知识转化为实际应用。</p><h1 id="11-总结"><a href="#11-总结" class="headerlink" title="11 总结"></a>11 总结</h1><h2 id="11-1-ADO-NET的优势和局限性"><a href="#11-1-ADO-NET的优势和局限性" class="headerlink" title="11.1 ADO.NET的优势和局限性"></a>11.1 ADO.NET的优势和局限性</h2><h3 id="11-1-1-优势"><a href="#11-1-1-优势" class="headerlink" title="11.1.1 优势"></a>11.1.1 优势</h3><ul><li><p><strong>性能：</strong> ADO.NET 提供了高性能的数据访问，支持连接池和参数化查询，提高了数据库操作的效率。</p></li><li><p><strong>灵活性：</strong> ADO.NET 提供了多种数据访问组件，如连接对象、命令对象、数据读取器等，使得开发人员可以根据需要灵活选择合适的组件。</p></li><li><p><strong>与数据库的广泛兼容性：</strong> ADO.NET 可以与多种数据库系统进行集成，包括但不限于 Microsoft SQL Server、MySQL、Oracle 等。</p></li><li><p><strong>事务支持：</strong> ADO.NET 提供了对事务的良好支持，开发人员可以通过事务来确保数据库操作的原子性、一致性、隔离性和持久性。</p></li></ul><h3 id="11-1-2-局限性"><a href="#11-1-2-局限性" class="headerlink" title="11.1.2 局限性"></a>11.1.2 局限性</h3><ul><li><p><strong>手动管理连接：</strong> ADO.NET 需要开发人员手动管理数据库连接的打开和关闭，如果不谨慎，可能会导致连接未正确关闭而产生资源泄漏。</p></li><li><p><strong>较低的抽象级别：</strong> ADO.NET 的较低抽象级别可能使一些开发任务相对繁琐，相较于一些 ORM 框架，需要更多手动操作。</p></li><li><p><strong>与数据库紧耦合：</strong> 使用 ADO.NET 进行数据库操作时，应用程序与特定数据库的交互较为紧密，切换数据库系统时可能需要进行较大的改动。</p></li></ul><h2 id="11-2-推荐学习资源"><a href="#11-2-推荐学习资源" class="headerlink" title="11.2 推荐学习资源"></a>11.2 推荐学习资源</h2><h3 id="11-2-1-官方文档"><a href="#11-2-1-官方文档" class="headerlink" title="11.2.1 官方文档"></a>11.2.1 官方文档</h3><ul><li><a href="https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/">Microsoft ADO.NET Documentation</a></li></ul><p>通过深入学习和实践，你可以更好地掌握 ADO.NET，并将其应用于实际项目中。希望读者能够在使用ADO.NET中取得良好的效果，不断提升自己的数据访问和处理能力。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-引言&quot;&gt;&lt;a href=&quot;#1-引言&quot; class=&quot;headerlink&quot; title=&quot;1. 引言&quot;&gt;&lt;/a&gt;1. 引言&lt;/h2&gt;&lt;h3 id=&quot;1-1-ADO-NET简介&quot;&gt;&lt;a href=&quot;#1-1-ADO-NET简介&quot; class=&quot;headerli</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>SQL Server 存储过程语法教程</title>
    <link href="http://www.loquy.cn/posts/ce3c51f7.html"/>
    <id>http://www.loquy.cn/posts/ce3c51f7.html</id>
    <published>2023-10-11T08:57:28.000Z</published>
    <updated>2023-10-11T08:57:28.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-什么是存储过程？"><a href="#1-什么是存储过程？" class="headerlink" title="1. 什么是存储过程？"></a>1. 什么是存储过程？</h2><p>存储过程（Stored Procedure）是一种在 SQL Server 数据库中定义的可执行的、可重用的数据库对象。它包含了一组 SQL 语句和控制结构，用于执行特定的任务或操作。存储过程通常具有以下特点：</p><ol><li><p><strong>封装性</strong>：存储过程将一系列 SQL 语句封装在一个单一的命名单元中。这有助于组织和管理数据库逻辑，同时也提高了数据的安全性，因为用户无法直接访问存储过程中的 SQL 语句。</p></li><li><p><strong>可重用性</strong>：存储过程可以在不同的地方和时间被多次调用。这使得相同的操作可以在多个地方使用，从而提高了代码的重用性。</p></li><li><p><strong>性能优化</strong>：存储过程可以被 SQL Server 编译和优化，以提高执行效率。存储过程的执行计划可以被缓存，减少了重复编译的开销。</p></li><li><p><strong>安全性</strong>：存储过程可以控制对数据库对象的访问权限。只有具有执行权限的用户或应用程序才能执行存储过程。</p></li><li><p><strong>参数化</strong>：存储过程可以接受参数，从外部传递数据给存储过程，使其更加通用和灵活。</p></li><li><p><strong>减少网络流量</strong>：通过将一组操作放在数据库内部执行，可以减少网络传输的数据量，提高应用程序性能。</p></li></ol><p>总之，存储过程是 SQL Server 数据库管理和应用程序开发中的重要工具，能够提高性能、安全性和代码的可维护性。它们在执行常见的数据库操作和数据处理任务时非常有用。</p><h2 id="2-存储过程的创建、删除、更新"><a href="#2-存储过程的创建、删除、更新" class="headerlink" title="2. 存储过程的创建、删除、更新"></a>2. 存储过程的创建、删除、更新</h2><p>创建存储过程是使用 SQL Server 数据库的关键任务之一。存储过程是数据库对象，包含一组 SQL 语句和逻辑，它们可以在需要时被调用。以下是关于创建存储过程的步骤和示例。</p><h3 id="创建存储过程的语法"><a href="#创建存储过程的语法" class="headerlink" title="创建存储过程的语法"></a>创建存储过程的语法</h3><p>在 SQL Server 中，创建存储过程的一般语法如下：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> ProcedureName<br>    <span class="hljs-variable">@Parameter1</span> DataType,<br>    <span class="hljs-variable">@Parameter2</span> DataType<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 存储过程的主体逻辑</span><br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><ul><li><code>CREATE PROCEDURE</code> 语句用于声明你要创建一个存储过程。</li><li><code>ProcedureName</code> 是存储过程的名称，你可以根据需要自定义名称。</li><li><code>@Parameter1</code> 和 <code>@Parameter2</code> 是存储过程的参数，你可以定义零个或多个参数。</li><li><code>DataType</code> 是参数的数据类型，例如 <code>INT</code>、<code>VARCHAR</code> 等。</li><li><code>AS</code> 关键字用于标识存储过程的主体逻辑的开始。</li><li><code>BEGIN</code> 和 <code>END</code> 用于包裹存储过程的实际操作。</li></ul><h3 id="参数的定义与传递"><a href="#参数的定义与传递" class="headerlink" title="参数的定义与传递"></a>参数的定义与传递</h3><p>存储过程可以接受参数，这使得它们可以更通用和灵活。参数分为输入参数和输出参数：</p><ul><li><strong>输入参数</strong>：用于传递数据给存储过程，在存储过程内部使用。</li><li><strong>输出参数</strong>：用于从存储过程中返回数据给调用方。</li></ul><p>以下是一个示例，演示如何创建一个简单的存储过程：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> GetEmployee<br>    <span class="hljs-variable">@EmployeeID</span> <span class="hljs-type">INT</span><br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> Employees <span class="hljs-keyword">WHERE</span> EmployeeID <span class="hljs-operator">=</span> <span class="hljs-variable">@EmployeeID</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，我们创建了一个名为 <code>GetEmployee</code> 的存储过程，它接受一个输入参数 <code>@EmployeeID</code>，并根据这个参数返回相应的员工信息。</p><h3 id="示例：创建一个简单的存储过程"><a href="#示例：创建一个简单的存储过程" class="headerlink" title="示例：创建一个简单的存储过程"></a>示例：创建一个简单的存储过程</h3><p>以下是一个更详细的示例，展示如何创建一个简单的存储过程，它接受两个参数，执行一个查询，并返回结果：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> GetSalesData<br>    <span class="hljs-variable">@StartDate</span> <span class="hljs-type">DATE</span>,<br>    <span class="hljs-variable">@EndDate</span> <span class="hljs-type">DATE</span><br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">SELECT</span> SalesDate, TotalSales<br>    <span class="hljs-keyword">FROM</span> Sales<br>    <span class="hljs-keyword">WHERE</span> SalesDate <span class="hljs-keyword">BETWEEN</span> <span class="hljs-variable">@StartDate</span> <span class="hljs-keyword">AND</span> <span class="hljs-variable">@EndDate</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，存储过程名为 <code>GetSalesData</code>，它接受两个日期参数 <code>@StartDate</code> 和 <code>@EndDate</code>，并返回在指定日期范围内的销售数据。</p><p>创建存储过程是 SQL Server 数据库管理和应用程序开发中的基本技能之一。它们可以用于执行各种数据库操作，从简单的查询到复杂的数据处理。存储过程的创建是数据库开发的重要一步，使你能够更好地组织和管理数据库逻辑。</p><p>当你创建存储过程后，你可能需要对其进行修改或删除。这两个操作同样在数据库开发中非常重要。让我们看看如何进行存储过程的修改和删除。</p><h3 id="修改存储过程"><a href="#修改存储过程" class="headerlink" title="修改存储过程"></a>修改存储过程</h3><p>要修改现有的存储过程，你可以使用 <code>ALTER PROCEDURE</code> 语句，并提供新的存储过程定义。以下是一个示例，演示如何修改存储过程的参数：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">PROCEDURE</span> GetSalesData<br>    <span class="hljs-variable">@StartDate</span> <span class="hljs-type">DATE</span>,<br>    <span class="hljs-variable">@EndDate</span> <span class="hljs-type">DATE</span>,<br>    <span class="hljs-variable">@Category</span> <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">50</span>)<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">SELECT</span> SalesDate, TotalSales<br>    <span class="hljs-keyword">FROM</span> Sales<br>    <span class="hljs-keyword">WHERE</span> SalesDate <span class="hljs-keyword">BETWEEN</span> <span class="hljs-variable">@StartDate</span> <span class="hljs-keyword">AND</span> <span class="hljs-variable">@EndDate</span><br>    <span class="hljs-keyword">AND</span> Category <span class="hljs-operator">=</span> <span class="hljs-variable">@Category</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在此示例中，我们添加了一个新的参数 <code>@Category</code> 到存储过程 <code>GetSalesData</code>，以便在查询中使用。这使你可以扩展存储过程的功能，以满足新的需求。</p><h3 id="删除存储过程"><a href="#删除存储过程" class="headerlink" title="删除存储过程"></a>删除存储过程</h3><p>要删除存储过程，可以使用 <code>DROP PROCEDURE</code> 语句，后跟存储过程的名称。以下是一个示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">PROCEDURE</span> GetSalesData;<br></code></pre></td></tr></table></figure><p>这将永久删除名为 <code>GetSalesData</code> 的存储过程。请小心使用此命令，因为它无法恢复已删除的存储过程。在删除存储过程之前，确保你不再需要它，或者在删除之前创建备份。</p><p>修改和删除存储过程是数据库维护和开发中的常见任务，它们使你能够适应数据库结构和业务需求的变化。通过使用 <code>ALTER PROCEDURE</code> 和 <code>DROP PROCEDURE</code> 语句，你可以轻松管理存储过程，以确保数据库的有效性和一致性。</p><h2 id="3-存储过程的执行"><a href="#3-存储过程的执行" class="headerlink" title="3. 存储过程的执行"></a>3. 存储过程的执行</h2><p>存储过程可以通过多种方式执行，包括直接执行和从应用程序代码中调用。下面将介绍不同的执行方式，包括不指定变量名直接传值的方式。</p><h3 id="直接执行存储过程"><a href="#直接执行存储过程" class="headerlink" title="直接执行存储过程"></a>直接执行存储过程</h3><p>在 SQL Server 中，你可以使用 <code>EXEC</code> 语句来直接执行存储过程。以下是一些执行方式的示例：</p><p><strong>方式1：指定参数名和值</strong></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> MyStoredProcedure <span class="hljs-variable">@Parameter1</span> <span class="hljs-operator">=</span> Value1, <span class="hljs-variable">@Parameter2</span> <span class="hljs-operator">=</span> Value2;<br></code></pre></td></tr></table></figure><p>在这种方式下，参数名和值是显式指定的。</p><p><strong>方式2：只传递值</strong></p><p>如果存储过程的参数在定义时没有指定默认值，你可以只传递参数的值，无需指定参数名。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> MyStoredProcedure Value1, Value2;<br></code></pre></td></tr></table></figure><p>这种方式下，SQL Server 会按照参数在存储过程中的顺序依次匹配值。要小心使用这种方式，确保参数的顺序正确。</p><p><strong>方式3：使用参数名传递值</strong></p><p>你也可以直接使用参数名传递值，无需显式指定参数名。这种方式在参数顺序变化时尤其有用。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> MyStoredProcedure Value1, <span class="hljs-variable">@Parameter2</span> <span class="hljs-operator">=</span> Value2;<br></code></pre></td></tr></table></figure><h3 id="从应用程序代码中调用存储过程"><a href="#从应用程序代码中调用存储过程" class="headerlink" title="从应用程序代码中调用存储过程"></a>从应用程序代码中调用存储过程</h3><p>除了直接执行存储过程，你还可以从应用程序代码中调用存储过程。这通常使用数据库连接库（如 ADO.NET、Entity Framework 等）完成。以下是一个示例：</p><p><strong>使用 C# 和 ADO.NET</strong></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System.Data;<br><span class="hljs-keyword">using</span> System.Data.SqlClient;<br><br><span class="hljs-built_in">string</span> connectionString = <span class="hljs-string">&quot;your_connection_string&quot;</span>;<br><span class="hljs-built_in">int</span> parameter1 = <span class="hljs-number">42</span>;<br><span class="hljs-built_in">string</span> parameter2 = <span class="hljs-string">&quot;SomeValue&quot;</span>;<br><br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br><br>    <span class="hljs-keyword">using</span> (SqlCommand cmd = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;MyStoredProcedure&quot;</span>, connection))<br>    &#123;<br>        cmd.CommandType = CommandType.StoredProcedure;<br>        cmd.Parameters.AddWithValue(<span class="hljs-string">&quot;@Parameter1&quot;</span>, parameter1);<br>        cmd.Parameters.AddWithValue(<span class="hljs-string">&quot;@Parameter2&quot;</span>, parameter2);<br><br>        cmd.ExecuteNonQuery();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在这个示例中，我们使用 C# 和 ADO.NET 从应用程序代码中调用了名为 <code>MyStoredProcedure</code> 的存储过程，并传递了参数的值。这种方式在开发应用程序时非常常见，因为它允许你通过应用程序与数据库交互。</p><p>无论你是在 SQL 查询工具中直接执行存储过程，还是从应用程序代码中调用它，存储过程的执行方式取决于具体需求和编程环境。不同的方式提供了不同的灵活性和控制选项，以满足不同的应用场景。</p><h2 id="4-存储过程的参数"><a href="#4-存储过程的参数" class="headerlink" title="4. 存储过程的参数"></a>4. 存储过程的参数</h2><p>存储过程是用于执行数据库操作的重要工具，它可以接受参数以便进行不同的数据处理。存储过程的参数分为输入参数和输出参数，它们使存储过程更加通用和灵活。</p><h3 id="输入参数"><a href="#输入参数" class="headerlink" title="输入参数"></a>输入参数</h3><p>输入参数用于将数据传递给存储过程，供其内部使用。在存储过程中，输入参数的值可以被引用和操作，但无法被更改。以下是定义输入参数的示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> MyStoredProcedure<br>    <span class="hljs-variable">@InputParameter1</span> DataType,<br>    <span class="hljs-variable">@InputParameter2</span> DataType<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 存储过程的主体逻辑</span><br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><ul><li><code>@InputParameter1</code> 和 <code>@InputParameter2</code> 是输入参数的名称。</li><li><code>DataType</code> 是参数的数据类型，可以是整数、字符、日期等。</li></ul><p>在存储过程内部，你可以使用这些输入参数执行各种操作，例如查询数据库、更新记录或计算结果。</p><h3 id="输出参数"><a href="#输出参数" class="headerlink" title="输出参数"></a>输出参数</h3><p>输出参数用于从存储过程中返回数据给调用方。输出参数可以在存储过程执行后包含特定的结果值。以下是定义输出参数的示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> MyStoredProcedure<br>    <span class="hljs-variable">@InputParameter</span> DataType,<br>    <span class="hljs-variable">@OutputParameter</span> DataType OUTPUT<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 存储过程的主体逻辑</span><br>    <span class="hljs-keyword">SET</span> <span class="hljs-variable">@OutputParameter</span> <span class="hljs-operator">=</span> SomeValue;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><ul><li><code>@OutputParameter</code> 带有 <code>OUTPUT</code> 关键字，表示它是一个输出参数。</li><li>存储过程内部可以使用 <code>SET</code> 语句来设置输出参数的值，以便在存储过程执行后返回给调用方。</li></ul><h3 id="使用参数传递数据"><a href="#使用参数传递数据" class="headerlink" title="使用参数传递数据"></a>使用参数传递数据</h3><p>存储过程参数的主要目的是传递数据。以下是如何在执行存储过程时传递参数的示例：</p><p><strong>在 <code>EXEC</code> 语句中传递参数值</strong></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> MyStoredProcedure <span class="hljs-variable">@InputParameter1</span> <span class="hljs-operator">=</span> Value1, <span class="hljs-variable">@InputParameter2</span> <span class="hljs-operator">=</span> Value2;<br></code></pre></td></tr></table></figure><p>在这里，<code>Value1</code> 和 <code>Value2</code> 是要传递给存储过程的具体值。</p><p><strong>从应用程序代码中调用存储过程</strong></p><p>在应用程序代码中，你可以使用数据库连接库（如 ADO.NET）来为存储过程的参数赋值，然后执行存储过程。以下是一个示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System.Data;<br><span class="hljs-keyword">using</span> System.Data.SqlClient;<br><br><span class="hljs-built_in">string</span> connectionString = <span class="hljs-string">&quot;your_connection_string&quot;</span>;<br><span class="hljs-built_in">int</span> inputParameter = <span class="hljs-number">42</span>;<br><br><span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>&#123;<br>    connection.Open();<br><br>    <span class="hljs-keyword">using</span> (SqlCommand cmd = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;MyStoredProcedure&quot;</span>, connection))<br>    &#123;<br>        cmd.CommandType = CommandType.StoredProcedure;<br>        cmd.Parameters.AddWithValue(<span class="hljs-string">&quot;@InputParameter&quot;</span>, inputParameter);<br><br>        <span class="hljs-comment">// 执行存储过程</span><br>        cmd.ExecuteNonQuery();<br><br>        <span class="hljs-comment">// 获取输出参数的值（如果有输出参数）</span><br>        <span class="hljs-keyword">var</span> outputValue = cmd.Parameters[<span class="hljs-string">&quot;@OutputParameter&quot;</span>].Value;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在应用程序代码中，你可以设置输入参数的值，并在存储过程执行后检索输出参数的值（如果有输出参数）。</p><p>存储过程参数使数据库操作更加灵活和通用。它们可以用于接受外部数据、执行特定的操作，并将结果返回给调用方，这是在数据库管理和应用程序开发中非常常见的需求。</p><h2 id="5-错误处理与异常"><a href="#5-错误处理与异常" class="headerlink" title="5. 错误处理与异常"></a>5. 错误处理与异常</h2><p>错误处理是存储过程开发中的一个重要方面，因为它确保了在执行期间出现问题时如何处理异常情况。SQL Server 提供了一些机制来处理错误和异常，包括 <code>TRY...CATCH</code> 块和 <code>RAISEERROR</code> 函数。</p><h3 id="TRY…CATCH-块"><a href="#TRY…CATCH-块" class="headerlink" title="TRY…CATCH 块"></a>TRY…CATCH 块</h3><p><code>TRY...CATCH</code> 块是一种用于处理异常的结构，允许你捕获并处理执行存储过程期间出现的错误。以下是 <code>TRY...CATCH</code> 块的基本结构：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">BEGIN</span> TRY<br>    <span class="hljs-comment">-- 可能引发错误的代码</span><br><span class="hljs-keyword">END</span> TRY<br><span class="hljs-keyword">BEGIN</span> CATCH<br>    <span class="hljs-comment">-- 处理错误的代码</span><br><span class="hljs-keyword">END</span> CATCH<br></code></pre></td></tr></table></figure><p>在 <code>TRY</code> 块中，你可以放置可能引发错误的代码。如果在 <code>TRY</code> 块中出现了错误，控制将转移到相应的 <code>CATCH</code> 块，其中可以处理错误，例如记录错误信息或执行特定的操作。</p><h3 id="RAISEERROR-函数"><a href="#RAISEERROR-函数" class="headerlink" title="RAISEERROR 函数"></a>RAISEERROR 函数</h3><p><code>RAISEERROR</code> 函数用于引发自定义错误消息，通常与 <code>TRY...CATCH</code> 块一起使用。它的语法如下：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql">RAISEERROR (MessageString, Severity, State);<br></code></pre></td></tr></table></figure><ul><li><code>MessageString</code> 是要显示的错误消息。</li><li><code>Severity</code> 是错误的严重性级别，通常在 0 到 25 之间，越高表示错误越严重。</li><li><code>State</code> 是错误状态码，通常用于标识错误的来源。</li></ul><p>以下是一个使用 <code>TRY...CATCH</code> 块和 <code>RAISEERROR</code> 函数的示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">BEGIN</span> TRY<br>    <span class="hljs-comment">-- 尝试执行可能引发错误的操作</span><br>    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span> <span class="hljs-operator">/</span> <span class="hljs-number">0</span>; <span class="hljs-comment">-- 这会引发除零错误</span><br><span class="hljs-keyword">END</span> TRY<br><span class="hljs-keyword">BEGIN</span> CATCH<br>    <span class="hljs-comment">-- 处理错误</span><br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@ErrorMessage</span> NVARCHAR(<span class="hljs-number">4000</span>) <span class="hljs-operator">=</span> ERROR_MESSAGE();<br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@ErrorSeverity</span> <span class="hljs-type">INT</span> <span class="hljs-operator">=</span> ERROR_SEVERITY();<br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@ErrorState</span> <span class="hljs-type">INT</span> <span class="hljs-operator">=</span> ERROR_STATE();<br><br>    <span class="hljs-comment">-- 记录错误信息</span><br>    RAISEERROR (<span class="hljs-variable">@ErrorMessage</span>, <span class="hljs-variable">@ErrorSeverity</span>, <span class="hljs-variable">@ErrorState</span>);<br><span class="hljs-keyword">END</span> CATCH<br></code></pre></td></tr></table></figure><p>在这个示例中，<code>TRY...CATCH</code> 块尝试执行一个除零操作，它会引发一个错误。<code>CATCH</code> 块捕获错误，记录错误信息，然后使用 <code>RAISEERROR</code> 函数引发自定义错误消息。</p><p>错误处理和异常处理是确保存储过程能够应对执行期间出现的问题的关键部分。通过使用 <code>TRY...CATCH</code> 块和 <code>RAISEERROR</code> 函数，你可以优雅地处理错误，记录相关信息，同时确保存储过程能够在出现问题时继续执行或提供有关问题的有用信息。</p><h2 id="6-存储过程中的控制流程"><a href="#6-存储过程中的控制流程" class="headerlink" title="6. 存储过程中的控制流程"></a>6. 存储过程中的控制流程</h2><p>存储过程不仅仅是一系列 SQL 语句的集合，还可以包含控制流程逻辑，这意味着你可以在存储过程中使用条件、循环和跳转等结构来实现更复杂的逻辑。以下是存储过程中常用的控制流程结构：</p><h3 id="1-IF…ELSE-语句"><a href="#1-IF…ELSE-语句" class="headerlink" title="1. IF…ELSE 语句"></a>1. IF…ELSE 语句</h3><p><code>IF...ELSE</code> 语句用于根据条件执行不同的代码块。它的基本语法如下：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql">IF <span class="hljs-keyword">Condition</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 在条件为真时执行的代码</span><br><span class="hljs-keyword">END</span><br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 在条件为假时执行的代码</span><br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><p>以下是一个示例，演示如何在存储过程中使用 <code>IF...ELSE</code>：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql">IF <span class="hljs-variable">@IsAdmin</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行管理员操作</span><br><span class="hljs-keyword">END</span><br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行普通用户操作</span><br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><h3 id="2-WHILE-循环"><a href="#2-WHILE-循环" class="headerlink" title="2. WHILE 循环"></a>2. WHILE 循环</h3><p><code>WHILE</code> 循环允许你多次执行一组语句，只要给定条件为真。它的语法如下：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs sql">WHILE <span class="hljs-keyword">Condition</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 循环体，可以包含多个语句</span><br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><p>以下是一个示例，演示如何在存储过程中使用 <code>WHILE</code> 循环：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@Counter</span> <span class="hljs-type">INT</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span>;<br>WHILE <span class="hljs-variable">@Counter</span> <span class="hljs-operator">&lt;=</span> <span class="hljs-number">10</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行循环内的操作</span><br>    <span class="hljs-keyword">SET</span> <span class="hljs-variable">@Counter</span> <span class="hljs-operator">=</span> <span class="hljs-variable">@Counter</span> <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;<br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><h3 id="3-GOTO-语句和标签的使用"><a href="#3-GOTO-语句和标签的使用" class="headerlink" title="3. GOTO 语句和标签的使用"></a>3. GOTO 语句和标签的使用</h3><p><code>GOTO</code> 语句和标签的组合允许你在存储过程中跳转到带有标签的代码块，通常用于处理错误、异常或特定条件下的控制流程。冒号 <code>:</code> 用于定义标签，标识代码块的起始点。虽然强大，但也潜在危险，应小心使用。以下是示例和用法：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- 标签的使用</span><br>ErrorHandling:<br><span class="hljs-comment">-- 错误处理逻辑</span><br><br><span class="hljs-comment">-- 在某个条件下跳转到标签</span><br>IF <span class="hljs-variable">@SomeCondition</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行某些操作</span><br><span class="hljs-keyword">END</span><br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">BEGIN</span><br>    GOTO ErrorHandling; <span class="hljs-comment">-- 跳转到错误处理代码块</span><br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><p>在上述示例中，<code>ErrorHandling</code> 后的冒号 <code>:</code> 标识了一个标签，用于标识错误处理代码块的起始点。当某个条件不满足时，通过 <code>GOTO</code> 语句，控制流程会跳转到标签 <code>ErrorHandling</code> 处执行相应的错误处理逻辑。标签和冒号的使用允许你在存储过程中灵活地管理控制流程，特别是在处理异常情况时非常有用。</p><h3 id="4-RETURN-语句"><a href="#4-RETURN-语句" class="headerlink" title="4. RETURN 语句"></a>4. RETURN 语句</h3><p><code>RETURN</code> 语句用于从存储过程中返回结果。它可以用于提前退出存储过程执行，也可以用于返回值。以下是一个示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs sql">IF <span class="hljs-variable">@SomeCondition</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行某些操作</span><br>    <span class="hljs-keyword">RETURN</span> <span class="hljs-number">0</span>; <span class="hljs-comment">-- 返回成功代码</span><br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><h3 id="5-使用逻辑运算符"><a href="#5-使用逻辑运算符" class="headerlink" title="5. 使用逻辑运算符"></a>5. 使用逻辑运算符</h3><p>你可以在存储过程中使用逻辑运算符（如 <code>AND</code> 和 <code>OR</code>）以及括号来构建复杂的条件表达式，以便更灵活地控制流程。这使你能够编写更复杂的条件和逻辑，以满足具体需求。以下是一个示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql">IF (<span class="hljs-variable">@IsAdmin</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-keyword">AND</span> <span class="hljs-variable">@HasPermission</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span>) <span class="hljs-keyword">OR</span> <span class="hljs-variable">@UserRole</span> <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;SuperAdmin&#x27;</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行某些操作</span><br><span class="hljs-keyword">END</span><br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 执行其他操作</span><br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure><p>这些控制流程结构使你能够编写更复杂的存储过程，可以根据条件执行不同的操作，循环执行操作，或者跳转到其他部分来处理不同的情况。但请小心使用，确保代码清晰可维护，以避免混乱和错误。</p><h2 id="7-返回数据"><a href="#7-返回数据" class="headerlink" title="7. 返回数据"></a>7. 返回数据</h2><p>在存储过程中，有多种方式可以返回数据给调用方或客户端应用程序，具体取决于存储过程的设计和需求。以下是一些常见的方法：</p><h3 id="1-使用-SELECT-语句"><a href="#1-使用-SELECT-语句" class="headerlink" title="1. 使用 SELECT 语句"></a>1. 使用 SELECT 语句</h3><p>最常见的方式是通过在存储过程中使用 <code>SELECT</code> 语句来返回数据集。这些数据可以被存储过程的调用方或客户端应用程序检索和处理。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> GetEmployees<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">SELECT</span> EmployeeID, FirstName, LastName <span class="hljs-keyword">FROM</span> Employees;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，存储过程 <code>GetEmployees</code> 使用 <code>SELECT</code> 语句返回了员工表中的数据。</p><h3 id="2-使用-OUTPUT-参数"><a href="#2-使用-OUTPUT-参数" class="headerlink" title="2. 使用 OUTPUT 参数"></a>2. 使用 OUTPUT 参数</h3><p>你可以在存储过程中定义输出参数，然后通过这些参数将数据返回给调用方。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> GetEmployeeName<br>    <span class="hljs-variable">@EmployeeID</span> <span class="hljs-type">INT</span>,<br>    <span class="hljs-variable">@EmployeeName</span> NVARCHAR(<span class="hljs-number">50</span>) OUTPUT<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">SELECT</span> <span class="hljs-variable">@EmployeeName</span> <span class="hljs-operator">=</span> FirstName <span class="hljs-operator">+</span> <span class="hljs-string">&#x27; &#x27;</span> <span class="hljs-operator">+</span> LastName<br>    <span class="hljs-keyword">FROM</span> Employees<br>    <span class="hljs-keyword">WHERE</span> EmployeeID <span class="hljs-operator">=</span> <span class="hljs-variable">@EmployeeID</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，存储过程 <code>GetEmployeeName</code> 接受一个输入参数 <code>@EmployeeID</code>，并将查询结果存储在输出参数 <code>@EmployeeName</code> 中。</p><h3 id="3-使用表变量或临时表"><a href="#3-使用表变量或临时表" class="headerlink" title="3. 使用表变量或临时表"></a>3. 使用表变量或临时表</h3><p>你可以在存储过程中创建表变量或临时表，将数据插入到这些表中，然后返回表的内容。这对于返回多个数据行或多个结果集非常有用。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> GetProductsByCategory<br>    <span class="hljs-variable">@CategoryID</span> <span class="hljs-type">INT</span><br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@Products</span> <span class="hljs-keyword">TABLE</span> (<br>        ProductID <span class="hljs-type">INT</span>,<br>        ProductName NVARCHAR(<span class="hljs-number">100</span>)<br>    );<br><br>    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-variable">@Products</span><br>    <span class="hljs-keyword">SELECT</span> ProductID, ProductName<br>    <span class="hljs-keyword">FROM</span> Products<br>    <span class="hljs-keyword">WHERE</span> CategoryID <span class="hljs-operator">=</span> <span class="hljs-variable">@CategoryID</span>;<br><br>    <span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> <span class="hljs-variable">@Products</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，存储过程 <code>GetProductsByCategory</code> 创建了一个表变量 <code>@Products</code>，将符合条件的产品数据插入到表中，然后通过 <code>SELECT</code> 语句返回表的内容。</p><h3 id="4-使用-XML-或-JSON"><a href="#4-使用-XML-或-JSON" class="headerlink" title="4. 使用 XML 或 JSON"></a>4. 使用 XML 或 JSON</h3><p>如果需要返回复杂的数据结构，你可以将结果转化为 XML 或 JSON 格式，然后将其返回给调用方。SQL Server 提供了内置函数和方法来处理 XML 和 JSON 数据。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> GetEmployeesAsJSON<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">SELECT</span> EmployeeID, FirstName, LastName<br>    <span class="hljs-keyword">FROM</span> Employees<br>    <span class="hljs-keyword">FOR</span> JSON AUTO;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，存储过程 <code>GetEmployeesAsJSON</code> 使用 <code>FOR JSON</code> 子句将查询结果以 JSON 格式返回。</p><h3 id="使用-RETURN-语句"><a href="#使用-RETURN-语句" class="headerlink" title="使用 RETURN 语句"></a>使用 RETURN 语句</h3><p><code>RETURN</code> 语句通常用于从存储过程中返回一个整数值，表示存储过程的执行状态或结果。这个返回值可以用于指示存储过程的成功或失败，或者返回其他自定义信息。</p><p>以下是一个示例，演示如何在存储过程中使用 <code>RETURN</code> 语句：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> CalculateSum<br>    <span class="hljs-variable">@Value1</span> <span class="hljs-type">INT</span>,<br>    <span class="hljs-variable">@Value2</span> <span class="hljs-type">INT</span><br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@Sum</span> <span class="hljs-type">INT</span>;<br><br>    <span class="hljs-keyword">SET</span> <span class="hljs-variable">@Sum</span> <span class="hljs-operator">=</span> <span class="hljs-variable">@Value1</span> <span class="hljs-operator">+</span> <span class="hljs-variable">@Value2</span>;<br><br>    IF <span class="hljs-variable">@Sum</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">100</span><br>    <span class="hljs-keyword">BEGIN</span><br>        <span class="hljs-comment">-- 存储过程执行成功</span><br>        <span class="hljs-keyword">RETURN</span> <span class="hljs-number">0</span>;<br>    <span class="hljs-keyword">END</span><br>    <span class="hljs-keyword">ELSE</span><br>    <span class="hljs-keyword">BEGIN</span><br>        <span class="hljs-comment">-- 存储过程执行失败</span><br>        <span class="hljs-keyword">RETURN</span> <span class="hljs-number">-1</span>;<br>    <span class="hljs-keyword">END</span><br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，存储过程 <code>CalculateSum</code> 接受两个整数参数，计算它们的和，并根据计算结果使用 <code>RETURN</code> 语句返回不同的值。如果和大于 100，存储过程返回 0，表示成功；否则，返回 -1，表示失败。</p><p>应用程序或客户端应用程序可以检查存储过程的返回值，以确定执行是否成功，然后根据需要采取进一步的操作。 <code>RETURN</code> 语句通常用于返回存储过程的状态或执行结果，但不用于返回数据集或查询结果。如果需要返回数据集，通常使用 <code>SELECT</code> 语句或输出参数。</p><p>无论使用哪种方法，存储过程可以根据具体需求返回不同类型的数据，包括单个值、数据集、XML、JSON 或其他自定义数据结构。数据的返回方式应根据应用程序的要求和数据交互的复杂性来选择。</p><h2 id="8-表值函数和标量函数"><a href="#8-表值函数和标量函数" class="headerlink" title="8. 表值函数和标量函数"></a>8. 表值函数和标量函数</h2><p>在 SQL Server 中，表值函数和标量函数是两种特殊类型的用户定义函数，它们允许你封装和重用 SQL 逻辑，以便在查询中使用。这些函数可以在存储过程中或 SQL 查询中发挥关键作用。</p><h3 id="表值函数（Table-Valued-Functions）"><a href="#表值函数（Table-Valued-Functions）" class="headerlink" title="表值函数（Table-Valued Functions）"></a>表值函数（Table-Valued Functions）</h3><p>表值函数是一种用户定义函数，它返回一个表作为结果。这允许你将表值函数的结果集嵌套到查询中，类似于从表中检索数据。有两种类型的表值函数：</p><ol><li><strong>内联表值函数（Inline Table-Valued Function）</strong>：这类函数返回一个结果集，并可以像表一样直接参与查询的 <code>FROM</code> 子句中。内联表值函数的结果集在查询中扮演了一个虚拟表的角色。</li></ol><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">FUNCTION</span> GetEmployeesByDepartment(<span class="hljs-variable">@DepartmentID</span> <span class="hljs-type">INT</span>)<br><span class="hljs-keyword">RETURNS</span> <span class="hljs-keyword">TABLE</span><br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">RETURN</span> (<br>    <span class="hljs-keyword">SELECT</span> EmployeeID, FirstName, LastName<br>    <span class="hljs-keyword">FROM</span> Employees<br>    <span class="hljs-keyword">WHERE</span> DepartmentID <span class="hljs-operator">=</span> <span class="hljs-variable">@DepartmentID</span><br>);<br></code></pre></td></tr></table></figure><p>这个内联表值函数接受一个部门 ID，返回该部门的所有员工。你可以在查询中像使用表一样调用它：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> GetEmployeesByDepartment(<span class="hljs-number">1</span>);<br></code></pre></td></tr></table></figure><ol start="2"><li><strong>多语句表值函数（Multi-Statement Table-Valued Function）</strong>：这类函数使用 <code>BEGIN...END</code> 块内的多条语句来生成结果集。它们允许更复杂的逻辑，但不能像内联表值函数那样直接嵌套在查询中。</li></ol><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">FUNCTION</span> GetHighSalaryEmployees()<br><span class="hljs-keyword">RETURNS</span> <span class="hljs-variable">@HighSalaryEmployees</span> <span class="hljs-keyword">TABLE</span><br>(<br>    EmployeeID <span class="hljs-type">INT</span>,<br>    FirstName NVARCHAR(<span class="hljs-number">50</span>),<br>    LastName NVARCHAR(<span class="hljs-number">50</span>)<br>)<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-variable">@HighSalaryEmployees</span><br>    <span class="hljs-keyword">SELECT</span> EmployeeID, FirstName, LastName<br>    <span class="hljs-keyword">FROM</span> Employees<br>    <span class="hljs-keyword">WHERE</span> Salary <span class="hljs-operator">&gt;</span> <span class="hljs-number">50000</span>;<br>    <span class="hljs-keyword">RETURN</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><h3 id="标量函数（Scalar-Functions）"><a href="#标量函数（Scalar-Functions）" class="headerlink" title="标量函数（Scalar Functions）"></a>标量函数（Scalar Functions）</h3><p>标量函数是一种用户定义函数，它返回单个标量值作为结果，例如整数、字符串或日期。标量函数通常用于计算、转换或处理数据。以下是一个标量函数的示例：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">FUNCTION</span> CalculateAge(<span class="hljs-variable">@BirthDate</span> <span class="hljs-type">DATE</span>)<br><span class="hljs-keyword">RETURNS</span> <span class="hljs-type">INT</span><br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@Age</span> <span class="hljs-type">INT</span>;<br>    <span class="hljs-keyword">SET</span> <span class="hljs-variable">@Age</span> <span class="hljs-operator">=</span> DATEDIFF(<span class="hljs-keyword">YEAR</span>, <span class="hljs-variable">@BirthDate</span>, GETDATE());<br>    <span class="hljs-keyword">RETURN</span> <span class="hljs-variable">@Age</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>这个标量函数接受出生日期，返回计算出的年龄。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> dbo.CalculateAge(<span class="hljs-string">&#x27;1990-01-01&#x27;</span>); <span class="hljs-comment">-- 使用标量函数计算年龄</span><br></code></pre></td></tr></table></figure><p>表值函数和标量函数可以在 SQL 查询中使用，以实现更灵活的数据操作和逻辑封装。它们可以用于简化查询、减少重复性代码，提高可维护性，并提供更强大的数据操作功能。</p><p>当谈到表值函数、标量函数以及存储过程时，有一些关键区别需要理解。下面我将为你提供示例，并解释这三者之间的不同之处。</p><h3 id="与存储过程的区别"><a href="#与存储过程的区别" class="headerlink" title="与存储过程的区别"></a>与存储过程的区别</h3><p>下面是一个表格，描述了函数和存储过程之间的关键区别：</p><table><thead><tr><th>特征</th><th>函数</th><th>存储过程</th></tr></thead><tbody><tr><td>返回值</td><td>返回一个值或表</td><td>通常不返回值，可以执行一系列操作</td></tr><tr><td>用途</td><td>通常用于封装计算、数据处理或转换逻辑</td><td>用于执行数据操作、事务管理、错误处理等</td></tr><tr><td>执行方式</td><td>可以在查询中直接使用，嵌套在查询中</td><td>通常需要使用 <code>EXEC</code> 或 <code>CALL</code> 显式执行</td></tr><tr><td>事务</td><td>可以在事务中调用，但通常不引起事务的隐式启动或提交</td><td>可以包含事务管理逻辑，例如启动、提交或回滚事务</td></tr><tr><td>修改数据库</td><td>通常不用于直接修改数据库中的数据</td><td>通常用于执行更新、插入、删除等操作，可以修改数据库中的数据</td></tr><tr><td>数据操作类型</td><td>可能包括 <code>SELECT</code> 查询、计算、数据处理等</td><td>包括更新、插入、删除、错误处理等数据操作</td></tr></tbody></table><p>这个表格强调了函数和存储过程之间的重要区别，尤其是在返回值、用途和执行方式方面。选择使用哪种方式应根据具体需求和任务的性质来决定。</p><h2 id="9-事务管理"><a href="#9-事务管理" class="headerlink" title="9. 事务管理"></a>9. 事务管理</h2><p>在 SQL Server 中，事务管理是数据库管理的关键部分。事务是一组 SQL 操作，要么全部成功执行，要么全部失败并回滚到之前的状态。这确保了数据库的一致性和可靠性。SQL Server 提供了多种方法来管理事务，包括显式事务和隐式事务。</p><h3 id="显式事务"><a href="#显式事务" class="headerlink" title="显式事务"></a>显式事务</h3><p>显式事务是由开发者显式指定和控制的事务。它们通常用于复杂的数据库操作，确保多个 SQL 语句要么全部执行成功，要么全部失败。显式事务通常使用以下关键字来定义和管理：</p><ul><li><code>BEGIN TRANSACTION</code>：开始一个新事务。</li><li><code>COMMIT</code>：提交当前事务，如果一切正常，事务中的更改将保存到数据库。</li><li><code>ROLLBACK</code>：回滚当前事务，如果出现错误，事务中的更改将被撤销。</li></ul><p>以下是一个示例，演示如何使用显式事务管理：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">BEGIN</span> TRANSACTION;<br><br><span class="hljs-keyword">UPDATE</span> Accounts <span class="hljs-keyword">SET</span> Balance <span class="hljs-operator">=</span> Balance <span class="hljs-operator">-</span> <span class="hljs-number">100</span> <span class="hljs-keyword">WHERE</span> AccountID <span class="hljs-operator">=</span> <span class="hljs-number">1</span>;<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> Transactions (AccountID, Amount) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-number">-100</span>);<br><br><span class="hljs-comment">-- 检查其他条件，如果不符合条件则回滚事务</span><br>IF <span class="hljs-variable">@SomeCondition</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">ROLLBACK</span>;<br>    PRINT <span class="hljs-string">&#x27;Transaction rolled back.&#x27;</span>;<br><span class="hljs-keyword">END</span><br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">COMMIT</span>;<br>    PRINT <span class="hljs-string">&#x27;Transaction committed.&#x27;</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><h3 id="隐式事务"><a href="#隐式事务" class="headerlink" title="隐式事务"></a>隐式事务</h3><p>隐式事务是在不明确声明事务的情况下自动启动的事务。通常，每个 SQL 语句都在自己的事务内运行。如果 SQL Server 检测到错误，它将回滚当前事务。如果一切正常，它将自动提交当前事务。</p><p>以下是一个示例，演示隐式事务的工作方式：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- 如果任何语句失败，SQL Server 将自动回滚事务</span><br><span class="hljs-keyword">UPDATE</span> Employees <span class="hljs-keyword">SET</span> Salary <span class="hljs-operator">=</span> Salary <span class="hljs-operator">+</span> <span class="hljs-number">500</span> <span class="hljs-keyword">WHERE</span> Department <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;HR&#x27;</span>;<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> Transactions (EmployeeID, Amount) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">123</span>, <span class="hljs-number">500</span>);<br></code></pre></td></tr></table></figure><h3 id="保存点（Savepoints）"><a href="#保存点（Savepoints）" class="headerlink" title="保存点（Savepoints）"></a>保存点（Savepoints）</h3><p>SQL Server 允许你在事务中设置保存点，以便在发生错误时回滚到特定的保存点，而不是回滚整个事务。这对于在事务中执行多个步骤并希望能够部分回滚时非常有用。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">BEGIN</span> TRANSACTION;<br><br><span class="hljs-comment">-- 步骤 1</span><br><span class="hljs-keyword">UPDATE</span> Products <span class="hljs-keyword">SET</span> Quantity <span class="hljs-operator">=</span> Quantity <span class="hljs-operator">-</span> <span class="hljs-number">10</span> <span class="hljs-keyword">WHERE</span> ProductID <span class="hljs-operator">=</span> <span class="hljs-number">1</span>;<br><br><span class="hljs-comment">-- 设置保存点</span><br>SAVE TRANSACTION Step1Complete;<br><br><span class="hljs-comment">-- 步骤 2</span><br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> Orders (ProductID, Quantity) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-number">10</span>);<br><br><span class="hljs-comment">-- 检查条件，如果不符合条件则回滚到保存点</span><br>IF <span class="hljs-variable">@SomeCondition</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">ROLLBACK</span> TRANSACTION Step1Complete;<br>    PRINT <span class="hljs-string">&#x27;Rolled back to Step 1.&#x27;</span>;<br><span class="hljs-keyword">END</span><br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">COMMIT</span>;<br>    PRINT <span class="hljs-string">&#x27;Transaction committed.&#x27;</span>;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>在这个示例中，如果某些条件不满足，事务将回滚到保存点 <code>Step1Complete</code>，仅回滚第一步骤的更改。</p><p>事务管理是确保数据库操作的一致性和可靠性的重要组成部分。通过使用显式或隐式事务以及保存点，你可以有效地管理事务，以适应不同的业务需求。</p><h2 id="10-游标（Cursor）"><a href="#10-游标（Cursor）" class="headerlink" title="10. 游标（Cursor）"></a>10. 游标（Cursor）</h2><p>游标（Cursor）是一种数据库对象，用于在结果集中逐行浏览数据，通常用于对数据进行逐行处理。以下是游标的生命周期：</p><table><thead><tr><th>阶段</th><th>操作</th><th>示例</th></tr></thead><tbody><tr><td>游标声明和定义</td><td>声明游标并定义要检索的数据集</td><td>DECLARE cursor_name CURSOR FOR SELECT column1, column2 FROM table</td></tr><tr><td>游标打开</td><td>打开游标以准备开始数据检索</td><td>OPEN cursor_name</td></tr><tr><td>数据检索</td><td>逐行检索数据并存储在变量中</td><td>FETCH NEXT FROM cursor_name INTO @var1, @var2</td></tr><tr><td>处理操作</td><td>处理从游标中检索到的数据</td><td>在此执行数据操作和逻辑</td></tr><tr><td>游标关闭</td><td>关闭游标以释放数据库资源</td><td>CLOSE cursor_name</td></tr><tr><td>游标释放</td><td>释放游标以清除游标定义和声明</td><td>DEALLOCATE cursor_name</td></tr></tbody></table><p>下面是一个示例存储过程，使用游标遍历表中的数据：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> ProcessDataWithCursor<br><span class="hljs-keyword">AS</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@EmployeeID</span> <span class="hljs-type">INT</span>;<br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@FirstName</span> NVARCHAR(<span class="hljs-number">50</span>);<br>    <span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@LastName</span> NVARCHAR(<span class="hljs-number">50</span>);<br><br>    <span class="hljs-comment">-- 声明和打开游标</span><br>    <span class="hljs-keyword">DECLARE</span> EmployeeCursor <span class="hljs-keyword">CURSOR</span> <span class="hljs-keyword">FOR</span><br>    <span class="hljs-keyword">SELECT</span> EmployeeID, FirstName, LastName<br>    <span class="hljs-keyword">FROM</span> Employees;<br><br>    <span class="hljs-keyword">OPEN</span> EmployeeCursor;<br><br>    <span class="hljs-comment">-- 获取第一行数据</span><br>    <span class="hljs-keyword">FETCH</span> NEXT <span class="hljs-keyword">FROM</span> EmployeeCursor <span class="hljs-keyword">INTO</span> <span class="hljs-variable">@EmployeeID</span>, <span class="hljs-variable">@FirstName</span>, <span class="hljs-variable">@LastName</span>;<br><br>    <span class="hljs-comment">-- 开始循环处理数据</span><br>    WHILE @<span class="hljs-variable">@FETCH_STATUS</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span><br>    <span class="hljs-keyword">BEGIN</span><br>        <span class="hljs-comment">-- 在这里进行数据处理，可以执行任何操作</span><br>        PRINT <span class="hljs-string">&#x27;Employee: &#x27;</span> <span class="hljs-operator">+</span> <span class="hljs-variable">@FirstName</span> <span class="hljs-operator">+</span> <span class="hljs-string">&#x27; &#x27;</span> <span class="hljs-operator">+</span> <span class="hljs-variable">@LastName</span>;<br><br>        <span class="hljs-comment">-- 获取下一行数据</span><br>        <span class="hljs-keyword">FETCH</span> NEXT <span class="hljs-keyword">FROM</span> EmployeeCursor <span class="hljs-keyword">INTO</span> <span class="hljs-variable">@EmployeeID</span>, <span class="hljs-variable">@FirstName</span>, <span class="hljs-variable">@LastName</span>;<br>    <span class="hljs-keyword">END</span>;<br><br>    <span class="hljs-comment">-- 关闭和释放游标</span><br>    <span class="hljs-keyword">CLOSE</span> EmployeeCursor;<br>    <span class="hljs-keyword">DEALLOCATE</span> EmployeeCursor;<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><p>这个存储过程使用游标来遍历名为 <code>Employees</code> 的表中的员工数据。在游标内部，它获取每一行的员工数据，并可以对每一行数据执行自定义操作。游标在循环结束后被关闭和释放。</p><p>需要注意的是，使用游标可能会导致性能问题，特别是在处理大量数据时。因此，应该仔细考虑是否有更有效的方法来执行数据操作，例如使用集合操作（如 <code>UPDATE</code> 或 <code>INSERT INTO ... SELECT</code>）来替代游标。</p><h2 id="11-系统变量"><a href="#11-系统变量" class="headerlink" title="11. 系统变量"></a>11. 系统变量</h2><p>以下是这些常见系统变量的用法：</p><ol><li><p><code>@@ERROR</code>：用于检查最近一次 SQL 操作是否引发了错误。通常与 <code>TRY...CATCH</code> 块结合使用，以捕获和处理错误。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">BEGIN</span> TRY<br>    <span class="hljs-comment">-- 一些 SQL 操作</span><br><span class="hljs-keyword">END</span> TRY<br><span class="hljs-keyword">BEGIN</span> CATCH<br>    <span class="hljs-comment">-- 处理错误</span><br>    IF @<span class="hljs-variable">@ERROR</span> <span class="hljs-operator">&lt;&gt;</span> <span class="hljs-number">0</span><br>    <span class="hljs-keyword">BEGIN</span><br>        <span class="hljs-comment">-- 执行回滚等操作</span><br>        <span class="hljs-keyword">ROLLBACK</span>;<br>        <span class="hljs-comment">-- 记录错误信息</span><br>        PRINT <span class="hljs-string">&#x27;An error occurred: &#x27;</span> <span class="hljs-operator">+</span> <span class="hljs-built_in">CAST</span>(@<span class="hljs-variable">@ERROR</span> <span class="hljs-keyword">AS</span> NVARCHAR(<span class="hljs-number">10</span>));<br>    <span class="hljs-keyword">END</span><br><span class="hljs-keyword">END</span> CATCH<br></code></pre></td></tr></table></figure></li><li><p><code>@@IDENTITY</code>：用于获取最近插入的标识列的值，通常在 INSERT 操作之后使用。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> Customers (Name) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">&#x27;John Doe&#x27;</span>);<br><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@IDENTITY</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@ROWCOUNT</code>：用于确定最近的 SQL 语句影响了多少行，通常用于检查操作是否成功或获取受影响的行数。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> Products <span class="hljs-keyword">WHERE</span> Price <span class="hljs-operator">&lt;</span> <span class="hljs-number">10.00</span>;<br>IF @<span class="hljs-variable">@ROWCOUNT</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span><br>    PRINT <span class="hljs-string">&#x27;Deleted &#x27;</span> <span class="hljs-operator">+</span> <span class="hljs-built_in">CAST</span>(@<span class="hljs-variable">@ROWCOUNT</span> <span class="hljs-keyword">AS</span> NVARCHAR(<span class="hljs-number">10</span>)) <span class="hljs-operator">+</span> <span class="hljs-string">&#x27; rows.&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@FETCH_STATUS</code>：通常与游标一起使用，以检查 FETCH 操作的状态。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- 声明和打开游标</span><br><span class="hljs-keyword">DECLARE</span> EmployeeCursor <span class="hljs-keyword">CURSOR</span> <span class="hljs-keyword">FOR</span><br><span class="hljs-keyword">SELECT</span> EmployeeID, FirstName, LastName<br><span class="hljs-keyword">FROM</span> Employees;<br><br><span class="hljs-keyword">OPEN</span> EmployeeCursor;<br><br><span class="hljs-comment">-- 获取第一行数据</span><br><span class="hljs-keyword">FETCH</span> NEXT <span class="hljs-keyword">FROM</span> EmployeeCursor <span class="hljs-keyword">INTO</span> <span class="hljs-variable">@EmployeeID</span>, <span class="hljs-variable">@FirstName</span>, <span class="hljs-variable">@LastName</span>;<br><br><span class="hljs-comment">-- 检查 FETCH 操作的状态</span><br><span class="hljs-comment">-- 0：FETCH 操作成功，已经获得了一行或更多行。</span><br><span class="hljs-comment">-- 1：FETCH 操作失败或没有更多的行可供获取。</span><br><span class="hljs-comment">-- 2：游标未初始化。</span><br>IF @<span class="hljs-variable">@FETCH_STATUS</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span><br><span class="hljs-keyword">BEGIN</span><br>    <span class="hljs-comment">-- 数据获取成功</span><br>    PRINT <span class="hljs-string">&#x27;Employee: &#x27;</span> <span class="hljs-operator">+</span> <span class="hljs-variable">@FirstName</span> <span class="hljs-operator">+</span> <span class="hljs-string">&#x27; &#x27;</span> <span class="hljs-operator">+</span> <span class="hljs-variable">@LastName</span>;<br><span class="hljs-keyword">END</span><br></code></pre></td></tr></table></figure></li><li><p><code>@@TRANCOUNT</code>：用于跟踪事务的嵌套级别。通常与 BEGIN TRANSACTION 和 COMMIT&#x2F;ROLLBACK TRANSACTION 一起使用。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">BEGIN</span> TRANSACTION; <span class="hljs-comment">-- 嵌套事务级别 +1</span><br><span class="hljs-comment">-- 一些操作</span><br>IF @<span class="hljs-variable">@TRANCOUNT</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span><br>    <span class="hljs-keyword">COMMIT</span>; <span class="hljs-comment">-- 提交内部事务，嵌套级别 -1</span><br></code></pre></td></tr></table></figure></li><li><p><code>@@LANGUAGE</code>：用于更改当前会话的语言设置，可以影响错误消息和日期格式。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SET</span> <span class="hljs-keyword">LANGUAGE</span> <span class="hljs-string">&#x27;French&#x27;</span>;<br>PRINT <span class="hljs-string">&#x27;Current Language: &#x27;</span> <span class="hljs-operator">+</span> @<span class="hljs-variable">@LANGUAGE</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@CONNECTIONS</code>：用于获取当前数据库服务器的连接数，可用于监视服务器的负载。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@CONNECTIONS</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Number of Connections&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@CPU_BUSY</code>：用于获取 SQL Server 实例的 CPU 使用率，有助于监视服务器的性能。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@CPU_BUSY</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;CPU Usage&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@TOTAL_ERRORS</code>：用于获取 SQL Server 实例的总错误数，有助于监视服务器的错误情况。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@TOTAL_ERRORS</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Total Errors&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@PACK_RECEIVED</code> 和 <code>@@PACK_SENT</code>：用于监视网络数据包的接收和发送情况，有助于分析网络性能。</p>   <figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@PACK_RECEIVED</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Packets Received&#x27;</span>, @<span class="hljs-variable">@PACK_SENT</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Packets Sent&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@SERVERNAME</code>：用于获取 SQL Server 实例的名称，有助于标识服务器。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@SERVERNAME</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Server Name&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@SERVICENAME</code>：用于获取 SQL Server 实例的服务名称，这也可以用于标识服务器。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@SERVICENAME</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Service Name&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@VERSION</code>：用于获取 SQL Server 的版本信息，可以用于确定正在运行的 SQL Server 版本。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@VERSION</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;SQL Server Version&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>@@OPTIONS</code>：包含有关当前会话的选项设置，这可以用于查看当前会话的配置。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> @<span class="hljs-variable">@OPTIONS</span> <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;Session Options&#x27;</span>;<br></code></pre></td></tr></table></figure></li></ol><p>这些系统变量为性能监视、错误分析、服务器标识以及在数据库对象中控制流程、错误处理和获取与数据库操作相关信息提供了关键工具。</p><h2 id="12-系统存储过程"><a href="#12-系统存储过程" class="headerlink" title="12. 系统存储过程"></a>12. 系统存储过程</h2><p>以下是一些常见系统存储过程：</p><ol><li><p><code>sp_helpdb</code>：用于查看数据库的信息，包括数据库文件的路径、大小等。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_helpdb;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_who</code>：用于获取当前连接到 SQL Server 实例的会话信息，包括登录名、数据库、状态等。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_who;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_who2</code>：用于提供比 <code>sp_who</code> 更详细的会话信息，包括更多列和信息。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_who2;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_configure</code>：用于查看和更改 SQL Server 的配置选项。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_configure;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_executesql</code>：用于执行动态 SQL 语句，通常与参数化查询一起使用，以避免 SQL 注入攻击。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">DECLARE</span> <span class="hljs-variable">@sql</span> NVARCHAR(MAX);<br><span class="hljs-keyword">SET</span> <span class="hljs-variable">@sql</span> <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;SELECT * FROM MyTable WHERE ColumnName = @Value&#x27;</span>;<br><span class="hljs-keyword">EXEC</span> sp_executesql <span class="hljs-variable">@sql</span>, N<span class="hljs-string">&#x27;@Value INT&#x27;</span>, <span class="hljs-variable">@Value</span> <span class="hljs-operator">=</span> <span class="hljs-number">123</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_renamedb</code>：用于更改数据库的名称。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_renamedb <span class="hljs-string">&#x27;OldDatabaseName&#x27;</span>, <span class="hljs-string">&#x27;NewDatabaseName&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_spaceused</code>：用于获取数据库中表或索引的空间使用情况。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_spaceused <span class="hljs-string">&#x27;TableName&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_help</code>：用于查看数据库对象（表、视图等）的结构信息。</p> <figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_help <span class="hljs-string">&#x27;TableName&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_helptext</code>：用于查看存储过程、触发器或视图的定义文本。</p> <figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_helptext <span class="hljs-string">&#x27;StoredProcedureName&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p><code>sp_depends</code>：用于查看数据库对象之间的依赖关系，包括对象引用和被引用的关系。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">EXEC</span> sp_depends <span class="hljs-string">&#x27;ObjectName&#x27;</span>;<br></code></pre></td></tr></table></figure></li></ol><p>这些系统存储过程提供了各种功能，用于管理和监视 SQL Server 实例，获取有关数据库和对象的信息，以及执行各种任务，如动态 SQL 执行和配置查看。在实际使用中，根据需求选择适当的系统存储过程。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-什么是存储过程？&quot;&gt;&lt;a href=&quot;#1-什么是存储过程？&quot; class=&quot;headerlink&quot; title=&quot;1. 什么是存储过程？&quot;&gt;&lt;/a&gt;1. 什么是存储过程？&lt;/h2&gt;&lt;p&gt;存储过程（Stored Procedure）是一种在 SQL Serve</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="SQL Server" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/SQL-Server/"/>
    
    
    <category term="SQL" scheme="http://www.loquy.cn/tags/SQL/"/>
    
    <category term="SQL Server" scheme="http://www.loquy.cn/tags/SQL-Server/"/>
    
  </entry>
  
  <entry>
    <title>C# 定时同步数据思路</title>
    <link href="http://www.loquy.cn/posts/903dbbbd.html"/>
    <id>http://www.loquy.cn/posts/903dbbbd.html</id>
    <published>2023-09-08T07:43:29.000Z</published>
    <updated>2023-09-08T07:43:29.000Z</updated>
    
    <content type="html"><![CDATA[<p>在许多应用程序中，数据同步是一个关键的任务，用于保持应用程序的数据与外部源（如 API 或其他数据库）同步。这篇博客将介绍如何使用 C# 来实现定时数据同步的思路，以确保数据的准确性和一致性。</p><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>定时执行同步数据的程序，使用互斥锁或者信号量来控制程序的并发执行，确保定时任务在前一个任务完成之后再触发。<br>1.1. 发送网络请求，请求接口数据，构造数据对应的实体类。<br>1.2. 批量插入或批量更新到数据库 。<br>1.3. 把查询放到循环外减少查询次数，去除循环内重复的查询语句，O(n)-&gt;O(1) 减小时间复杂度。</li><li>减少锁表时间，需要过滤数据，减少数据量，然后进行同步。<br>2.1. 配置增量或全量同步，把接口数据分批次 IN 查询，然后和数据库的数据进行对比，不存在则更新 。<br>2.2. 配置同步天数，去同步多少天前的数据。</li></ol><h2 id="1-控制并发执行"><a href="#1-控制并发执行" class="headerlink" title="1. 控制并发执行"></a>1. 控制并发执行</h2><p>在定时执行同步数据的程序中，一个重要的考虑因素是如何控制程序的并发执行，以避免可能的冲突和数据不一致。这可以通过以下方式来实现：</p><h3 id="1-1-使用互斥锁或信号量"><a href="#1-1-使用互斥锁或信号量" class="headerlink" title="1.1 使用互斥锁或信号量"></a>1.1 使用互斥锁或信号量</h3><p>可以使用互斥锁（Mutex）或信号量（Semaphore）来确保定时任务在前一个任务完成之后再触发。这样可以防止多个任务同时执行，避免数据竞争和不一致性问题。</p><blockquote><p>定时同步，代码示例：</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Quartz;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Threading;<br><span class="hljs-keyword">using</span> System.Threading.Tasks;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">JobNamespace</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DataSyncJob</span> : <span class="hljs-title">IJob</span><br>    &#123;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> SemaphoreSlim semaphore = <span class="hljs-keyword">new</span> SemaphoreSlim(<span class="hljs-number">1</span>);<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Execute</span>(<span class="hljs-params">IJobExecutionContext context</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">try</span><br>            &#123;<br>                <span class="hljs-keyword">await</span> semaphore.WaitAsync();<br><br>                SyncData(<span class="hljs-string">&quot;示例&quot;</span>, () =&gt;<br>                &#123;<br>                    <span class="hljs-comment">// 执行数据同步操作</span><br>                &#125;);<br>            &#125;<br>            <span class="hljs-keyword">catch</span> (Exception ex)<br>            &#123;<br>                Console.WriteLine(<span class="hljs-string">$&quot;定时任务发生异常：<span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>            &#125;<br>            <span class="hljs-keyword">finally</span><br>            &#123;<br>                semaphore.Release();<br>            &#125;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SyncData</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> operationType, Action syncAction</span>)</span><br>        &#123;<br>            Console.WriteLine(<span class="hljs-string">$&quot;开始同步数据：<span class="hljs-subst">&#123;operationType&#125;</span>&quot;</span>);<br>            syncAction.Invoke();<br>            Console.WriteLine(<span class="hljs-string">$&quot;完成同步数据：<span class="hljs-subst">&#123;operationType&#125;</span>&quot;</span>);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Quartz.Impl;<br><span class="hljs-keyword">using</span> Quartz;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Threading.Tasks;<br><span class="hljs-keyword">using</span> JobNamespace.Job;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Demo</span><br>&#123;<br>    <span class="hljs-keyword">internal</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span><br>    &#123;<br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> 应用程序的主入口点。</span><br>        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span><br>        [<span class="hljs-meta">STAThread</span>]<br>        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>()</span><br>        &#123;<br>            <span class="hljs-comment">// 启动定时任务</span><br>            StartScheduler();<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartScheduler</span>()</span><br>        &#123;<br>            <span class="hljs-keyword">await</span> RunScheduler();<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">RunScheduler</span>()</span><br>        &#123;<br>            <span class="hljs-comment">// 创建调度器工厂</span><br>            ISchedulerFactory schedulerFactory = <span class="hljs-keyword">new</span> StdSchedulerFactory();<br>            IScheduler scheduler = <span class="hljs-keyword">await</span> schedulerFactory.GetScheduler();<br><br>            <span class="hljs-comment">// 创建一个触发器，使用 Cron 表达式触发定时任务</span><br>            ITrigger trigger = TriggerBuilder.Create()<br>                .WithIdentity(<span class="hljs-string">&quot;SyncDataTrigger&quot;</span>, <span class="hljs-string">&quot;Sync&quot;</span>)<br>                .WithCronSchedule(<span class="hljs-string">&quot;0/30 * * * * ?&quot;</span>) <span class="hljs-comment">// 每30秒触发一次</span><br>                .Build();<br><br>            <span class="hljs-comment">// 创建一个任务</span><br>            IJobDetail job = JobBuilder.Create&lt;SyncErpData&gt;()<br>                .WithIdentity(<span class="hljs-string">&quot;SyncDataJob&quot;</span>, <span class="hljs-string">&quot;Sync&quot;</span>)<br>                .Build();<br><br>            <span class="hljs-comment">// 将任务和触发器关联到调度器</span><br>            <span class="hljs-keyword">await</span> scheduler.ScheduleJob(job, trigger);<br><br>            <span class="hljs-comment">// 启动调度器</span><br>            <span class="hljs-keyword">await</span> scheduler.Start();<br>        &#125;<br><br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="2-数据请求和处理"><a href="#2-数据请求和处理" class="headerlink" title="2. 数据请求和处理"></a>2. 数据请求和处理</h2><p>在同步数据的过程中，需要执行以下步骤来获取和处理数据：</p><h3 id="2-1-发送网络请求"><a href="#2-1-发送网络请求" class="headerlink" title="2.1 发送网络请求"></a>2.1 发送网络请求</h3><p>首先，需要向外部源发送网络请求，以获取需要同步的数据。这通常涉及与外部 API 进行通信，然后将返回的数据转化为 C# 中的实体类。</p><blockquote><p>发送请求，代码示例：</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Net;<br><span class="hljs-keyword">using</span> System.Text;<br><span class="hljs-keyword">using</span> System.IO;<br><span class="hljs-keyword">using</span> Newtonsoft.Json;<br><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> T <span class="hljs-title">ExecutePostRequest</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-built_in">string</span> url, <span class="hljs-built_in">object</span> requestData</span>)</span><br>&#123;<br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);<br>        request.Method = <span class="hljs-string">&quot;POST&quot;</span>;<br>        request.ContentType = <span class="hljs-string">&quot;application/json&quot;</span>;<br><br>        <span class="hljs-built_in">string</span> jsonRequestData = JsonConvert.SerializeObject(requestData);<br>        <span class="hljs-built_in">byte</span>[] data = Encoding.UTF8.GetBytes(jsonRequestData);<br><br>        <span class="hljs-keyword">using</span> (Stream requestStream = request.GetRequestStream())<br>        &#123;<br>            requestStream.Write(data, <span class="hljs-number">0</span>, data.Length);<br>        &#125;<br><br>        <span class="hljs-keyword">using</span> (HttpWebResponse response = (HttpWebResponse)request.GetResponse())<br>        &#123;<br>            <span class="hljs-keyword">if</span> (response.StatusCode != HttpStatusCode.OK)<br>            &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$&quot;接口调用失败，状态码：<span class="hljs-subst">&#123;response.StatusCode&#125;</span>&quot;</span>);<br>            &#125;<br><br>            <span class="hljs-keyword">using</span> (Stream responseStream = response.GetResponseStream())<br>            <span class="hljs-keyword">using</span> (StreamReader reader = <span class="hljs-keyword">new</span> StreamReader(responseStream))<br>            &#123;<br>                <span class="hljs-built_in">string</span> jsonResponseData = reader.ReadToEnd();<br>                <span class="hljs-keyword">return</span> JsonConvert.DeserializeObject&lt;T&gt;(jsonResponseData);<br>            &#125;<br>        &#125;<br>    &#125;<br>    <span class="hljs-keyword">catch</span> (Exception ex)<br>    &#123;<br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$&quot;接口调用发生异常：<span class="hljs-subst">&#123;ex.Message&#125;</span>&quot;</span>);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h3 id="2-2-数据插入或更新"><a href="#2-2-数据插入或更新" class="headerlink" title="2.2 数据插入或更新"></a>2.2 数据插入或更新</h3><p>获取数据后，可以将其批量插入或批量更新到数据库中。这可以通过使用 SqlBulkCopy 来实现，以提高性能和效率。</p><blockquote><p>批量插入，代码示例：</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Collections.Generic;<br><span class="hljs-keyword">using</span> System.Data;<br><span class="hljs-keyword">using</span> System.Data.SqlClient;<br><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">BulkInsertOrders</span>(<span class="hljs-params">List&lt;Order&gt; orders, <span class="hljs-built_in">string</span> connectionString</span>)</span><br>&#123;<br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        <span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>        &#123;<br>            connection.Open();<br><br>            <span class="hljs-keyword">using</span> (SqlBulkCopy bulkCopy = <span class="hljs-keyword">new</span> SqlBulkCopy(connection))<br>            &#123;<br>                bulkCopy.DestinationTableName = <span class="hljs-string">&quot;Orders&quot;</span>; <span class="hljs-comment">// 表名</span><br>                bulkCopy.BatchSize = <span class="hljs-number">1000</span>; <span class="hljs-comment">// 每批次的行数</span><br>                bulkCopy.BulkCopyTimeout = <span class="hljs-number">60</span>; <span class="hljs-comment">// 超时时间（秒）</span><br><br>                <span class="hljs-comment">// 定义数据映射，将源数据列映射到目标表的列</span><br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;ID&quot;</span>, <span class="hljs-string">&quot;ReferenceID&quot;</span>);<br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;CustomerID&quot;</span>, <span class="hljs-string">&quot;CustomerID&quot;</span>);<br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;OrderDate&quot;</span>, <span class="hljs-string">&quot;OrderDate&quot;</span>);<br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;TotalAmount&quot;</span>, <span class="hljs-string">&quot;Amount&quot;</span>);<br><br>                DataTable dataTable = <span class="hljs-keyword">new</span> DataTable();<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;ID&quot;</span>, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">int</span>));<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;CustomerID&quot;</span>, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">int</span>));<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;OrderDate&quot;</span>, <span class="hljs-keyword">typeof</span>(DateTime));<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;TotalAmount&quot;</span>, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">decimal</span>));<br><br>                <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> order <span class="hljs-keyword">in</span> orders)<br>                &#123;<br>                    <span class="hljs-comment">// 将数据添加到DataTable</span><br>                    dataTable.Rows.Add(order.ID, order.CustomerID, order.OrderDate, order.TotalAmount);<br>                &#125;<br><br>                <span class="hljs-comment">// 执行批量插入</span><br>                bulkCopy.WriteToServer(dataTable);<br>            &#125;<br>        &#125;<br>    &#125;<br>    <span class="hljs-keyword">catch</span> (Exception ex)<br>    &#123;<br>        Console.WriteLine(<span class="hljs-string">&quot;批量插入失败：&quot;</span> + ex.Message);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><blockquote><p>批量更新，代码示例：</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Collections.Generic;<br><span class="hljs-keyword">using</span> System.Data;<br><span class="hljs-keyword">using</span> System.Data.SqlClient;<br><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">BulkUpdateOrders</span>(<span class="hljs-params">List&lt;Order&gt; updatedOrders, <span class="hljs-built_in">string</span> connectionString</span>)</span><br>&#123;<br>    <span class="hljs-keyword">try</span><br>    &#123;<br>        <span class="hljs-keyword">using</span> (SqlConnection connection = <span class="hljs-keyword">new</span> SqlConnection(connectionString))<br>        &#123;<br>            connection.Open();<br><br>            <span class="hljs-comment">// 创建一个临时表，用于存储要更新的数据</span><br>            <span class="hljs-keyword">using</span> (SqlBulkCopy bulkCopy = <span class="hljs-keyword">new</span> SqlBulkCopy(connection))<br>            &#123;<br>                bulkCopy.DestinationTableName = <span class="hljs-string">&quot;TempOrders&quot;</span>; <span class="hljs-comment">// 临时表名</span><br>                bulkCopy.BatchSize = <span class="hljs-number">1000</span>; <span class="hljs-comment">// 每批次的行数</span><br>                bulkCopy.BulkCopyTimeout = <span class="hljs-number">60</span>; <span class="hljs-comment">// 超时时间（秒）</span><br><br>                <span class="hljs-comment">// 定义数据映射，将源数据列映射到临时表的列</span><br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;ID&quot;</span>, <span class="hljs-string">&quot;ReferenceID&quot;</span>);<br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;CustomerID&quot;</span>, <span class="hljs-string">&quot;CustomerID&quot;</span>);<br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;OrderDate&quot;</span>, <span class="hljs-string">&quot;OrderDate&quot;</span>);<br>                bulkCopy.ColumnMappings.Add(<span class="hljs-string">&quot;TotalAmount&quot;</span>, <span class="hljs-string">&quot;Amount&quot;</span>);<br><br>                DataTable dataTable = <span class="hljs-keyword">new</span> DataTable();<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;ID&quot;</span>, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">int</span>));<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;CustomerID&quot;</span>, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">int</span>));<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;OrderDate&quot;</span>, <span class="hljs-keyword">typeof</span>(DateTime));<br>                dataTable.Columns.Add(<span class="hljs-string">&quot;TotalAmount&quot;</span>, <span class="hljs-keyword">typeof</span>(<span class="hljs-built_in">decimal</span>));<br><br>                <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> order <span class="hljs-keyword">in</span> updatedOrders)<br>                &#123;<br>                    <span class="hljs-comment">// 将要更新的数据添加到DataTable</span><br>                    dataTable.Rows.Add(order.ID, order.CustomerID, order.OrderDate, order.TotalAmount);<br>                &#125;<br><br>                <span class="hljs-comment">// 执行将数据插入到临时表的操作</span><br>                bulkCopy.WriteToServer(dataTable);<br>            &#125;<br><br>            <span class="hljs-comment">// 使用SQL语句执行批量更新操作</span><br>            <span class="hljs-keyword">using</span> (SqlCommand updateCommand = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;UPDATE [Orders] SET [CustomerID] = [Temp].[CustomerID], [OrderDate] = [Temp].[OrderDate], [TotalAmount] = [Temp].[Amount] FROM [Orders] INNER JOIN [TempOrders] AS [Temp] ON [Orders].[ReferenceID] = [Temp].[ID]&quot;</span>, connection))<br>            &#123;<br>                updateCommand.ExecuteNonQuery();<br>            &#125;<br><br>            <span class="hljs-comment">// 清空临时表</span><br>            <span class="hljs-keyword">using</span> (SqlCommand truncateCommand = <span class="hljs-keyword">new</span> SqlCommand(<span class="hljs-string">&quot;TRUNCATE TABLE [TempOrders]&quot;</span>, connection))<br>            &#123;<br>                truncateCommand.ExecuteNonQuery();<br>            &#125;<br>        &#125;<br>    &#125;<br>    <span class="hljs-keyword">catch</span> (Exception ex)<br>    &#123;<br>        Console.WriteLine(<span class="hljs-string">&quot;批量更新失败：&quot;</span> + ex.Message);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h3 id="2-3-减少查询次数"><a href="#2-3-减少查询次数" class="headerlink" title="2.3 减少查询次数"></a>2.3 减少查询次数</h3><p>为了优化性能，建议将查询操作放到循环外部，以减少查询次数。这可以通过在循环之外查询数据，然后在循环内部对数据进行处理，从而减少数据库查询的次数。这将大大降低时间复杂度，从 O(n) 减小到 O(1)。</p><h2 id="3-减少锁表时间"><a href="#3-减少锁表时间" class="headerlink" title="3. 减少锁表时间"></a>3. 减少锁表时间</h2><p>为了减少锁表时间，可以采取以下措施：</p><h3 id="3-1-数据过滤"><a href="#3-1-数据过滤" class="headerlink" title="3.1 数据过滤"></a>3.1 数据过滤</h3><p>在同步数据之前，可以对数据进行过滤，减少需要同步的数据量。这可以通过配置增量同步或全量同步来实现。对于增量同步，可以将接口数据分成批次，并将其与数据库数据进行对比，然后仅同步不存在的数据。对于全量同步，可以定期同步所有数据，确保数据的一致性。</p><blockquote><p>增量同步或全量同步，代码示例：</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Order&gt; <span class="hljs-title">FindOrdersToUpdate</span>(<span class="hljs-params">List&lt;Order&gt; orders, SqlTransaction transaction</span>)</span><br>&#123;<br>    <span class="hljs-built_in">bool</span> fullSync = ConfigReader.ReadConfigValue&lt;<span class="hljs-built_in">bool</span>&gt;(<span class="hljs-string">&quot;syncMode&quot;</span>);<br><br>    <span class="hljs-keyword">if</span> (fullSync)<br>    &#123;<br>        <span class="hljs-comment">// 全量更新</span><br>        <span class="hljs-keyword">return</span> orders;<br>    &#125;<br><br>    <span class="hljs-comment">// 增量更新</span><br>    List&lt;Order&gt; missingOrders = <span class="hljs-keyword">new</span> List&lt;Order&gt;();<br>    <span class="hljs-built_in">int</span> batchSize = <span class="hljs-number">100</span>;<br>    List&lt;Order&gt; ordersToRemove = <span class="hljs-keyword">new</span> List&lt;Order&gt;();<br><br>    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i &lt; orders.Count; i += batchSize)<br>    &#123;<br>        List&lt;Order&gt; batch = orders.Skip(i).Take(batchSize).ToList();<br><br>        <span class="hljs-built_in">string</span> inClause = <span class="hljs-built_in">string</span>.Join(<span class="hljs-string">&quot;,&quot;</span>, batch.Select(order =&gt; <span class="hljs-string">&quot;&#x27;&quot;</span> + order.ID.ToString() + <span class="hljs-string">&quot;&#x27;&quot;</span>));<br><br>        <span class="hljs-built_in">string</span> query = <span class="hljs-string">$&quot;SELECT [ReferenceID] FROM [dbo].[Orders] WHERE [ReferenceID] IN (<span class="hljs-subst">&#123;inClause&#125;</span>)&quot;</span>;<br>        <span class="hljs-keyword">using</span> (SqlCommand cmd = <span class="hljs-keyword">new</span> SqlCommand(query, transaction.Connection, transaction))<br>        &#123;<br>            <span class="hljs-keyword">using</span> (SqlDataReader reader = cmd.ExecuteReader())<br>            &#123;<br>                <span class="hljs-keyword">while</span> (reader.Read())<br>                &#123;<br>                    <span class="hljs-keyword">if</span> (!reader.IsDBNull(<span class="hljs-number">0</span>))<br>                    &#123;<br>                        <span class="hljs-built_in">string</span> referenceID = reader.GetString(<span class="hljs-number">0</span>);<br>                        <span class="hljs-keyword">var</span> matchingOrder = batch.FirstOrDefault(order =&gt; order.ID == Convert.ToInt32(referenceID));<br><br>                        <span class="hljs-keyword">if</span> (matchingOrder != <span class="hljs-literal">null</span>)<br>                        &#123;<br>                            ordersToRemove.Add(matchingOrder);<br>                        &#125;<br>                    &#125;<br>                &#125;<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">// 执行删除操作</span><br>    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> orderToRemove <span class="hljs-keyword">in</span> ordersToRemove)<br>    &#123;<br>        orders.Remove(orderToRemove);<br>    &#125;<br><br>    <span class="hljs-keyword">return</span> orders;<br>&#125;<br><br></code></pre></td></tr></table></figure><h3 id="3-2-同步天数配置"><a href="#3-2-同步天数配置" class="headerlink" title="3.2 同步天数配置"></a>3.2 同步天数配置</h3><p>可以配置同步天数，以确定要同步多少天前的数据。这有助于控制同步的范围，并避免同步过多的历史数据，从而减少锁表时间。</p><blockquote><p>读取 Json 配置文件，代码示例：</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Newtonsoft.Json.Linq;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Collections.Generic;<br><span class="hljs-keyword">using</span> System.Linq;<br><span class="hljs-keyword">using</span> System.Text;<br><span class="hljs-keyword">using</span> System.Threading.Tasks;<br><span class="hljs-keyword">using</span> System.IO;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Demo</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ConfigReader</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> T <span class="hljs-title">ReadConfigValue</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-built_in">string</span> settingName, <span class="hljs-built_in">string</span> configFilePath = <span class="hljs-string">&quot;config.json&quot;</span></span>)</span><br>        &#123;<br>            <span class="hljs-built_in">string</span> configJson = File.ReadAllText(configFilePath);<br><br>            JObject config = JObject.Parse(configJson);<br><br>            <span class="hljs-keyword">if</span> (config.TryGetValue(settingName, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> <span class="hljs-keyword">value</span>))<br>            &#123;<br>                <span class="hljs-keyword">try</span><br>                &#123;<br>                    <span class="hljs-keyword">return</span> (T)Convert.ChangeType(<span class="hljs-keyword">value</span>.ToString(), <span class="hljs-keyword">typeof</span>(T));<br>                &#125;<br>                <span class="hljs-keyword">catch</span><br>                &#123;<br>                    <span class="hljs-comment">// 转换失败，返回默认值</span><br>                    <span class="hljs-keyword">return</span> <span class="hljs-literal">default</span>(T);<br>                &#125;<br>            &#125;<br><br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">default</span>(T);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-comment">// 读取配置文件</span><br><span class="hljs-built_in">bool</span> isFullSync = ConfigReader.ReadConfigValue&lt;<span class="hljs-built_in">bool</span>&gt;(<span class="hljs-string">&quot;isFullSync&quot;</span>);<br><span class="hljs-built_in">int</span> syncDay = ConfigReader.ReadConfigValue&lt;<span class="hljs-built_in">int</span>&gt;(<span class="hljs-string">&quot;SyncDay&quot;</span>);<br>syncDay = Math.Max(syncDay, <span class="hljs-number">0</span>);<br></code></pre></td></tr></table></figure><p>通过以上的思路和方法，可以有效地实现定时数据同 步任务，并确保数据的准确性、一致性和性能。这将有助于维护应用程序的数据质量和稳定性。希望本篇博客对你理解和实现 C# 数据同步任务有所帮助。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在许多应用程序中，数据同步是一个关键的任务，用于保持应用程序的数据与外部源（如 API 或其他数据库）同步。这篇博客将介绍如何使用 C# 来实现定时数据同步的思路，以确保数据的准确性和一致性。&lt;/p&gt;
&lt;h2 id=&quot;思路&quot;&gt;&lt;a href=&quot;#思路&quot; class=&quot;hea</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>用 C# 编写日志文件</title>
    <link href="http://www.loquy.cn/posts/ef2f8f88.html"/>
    <id>http://www.loquy.cn/posts/ef2f8f88.html</id>
    <published>2023-08-15T05:41:27.000Z</published>
    <updated>2023-08-15T05:41:27.000Z</updated>
    
    <content type="html"><![CDATA[<p>在软件开发中，日志记录是一项至关重要的任务，它可以帮助我们跟踪应用程序的状态、故障排除和性能优化。在本篇博客中，我们将深入介绍一个用于日志记录的 C# 类库，展示其如何实现灵活、可靠且易于使用的特性。</p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>在开发过程中，我们常常需要记录应用程序的运行状态、异常情况和重要事件，以便后续分析和调试。传统的日志记录方式可能相对繁琐且难以管理，而这个 C# 类库则提供了一个高效的解决方案，可以帮助开发人员更轻松地实现日志记录功能。</p><h3 id="功能概述"><a href="#功能概述" class="headerlink" title="功能概述"></a>功能概述</h3><p>这个 C# 类库（命名为 <code>LogWrite</code>）旨在提供一个灵活、可靠且易于使用的日志记录工具。它具有以下主要功能：</p><ol><li><p><strong>日志写入功能</strong>：提供了三个不同的方法来写入日志，分别是 <code>WriteLog</code>、<code>WriteLogWithSQL</code> 和 <code>WriteLogWithException</code>。开发人员可以根据需要选择适当的方法，并附加额外的信息，如执行的 SQL 语句或异常信息。</p></li><li><p><strong>日志文件夹管理</strong>：类库会自动创建日志文件夹，以确保日志文件的安全存储。如果日志文件夹不存在，它会在需要时自动创建。</p></li><li><p><strong>日志文件清理</strong>：提供了 <code>DeleteLog</code> 方法，可以删除指定文件夹中过期的日志文件。这有助于保持日志文件夹的整洁，并避免占用过多磁盘空间。</p></li><li><p><strong>日志编号</strong>：每条日志都带有一个唯一的编号，以帮助区分不同的日志条目。该编号会自动递增，确保日志的顺序和唯一性。</p></li></ol><h3 id="代码解析"><a href="#代码解析" class="headerlink" title="代码解析"></a>代码解析</h3><p>以下是<code>LogWrite</code> 类的详细代码示例：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.IO;<br><span class="hljs-keyword">using</span> System.Text.RegularExpressions;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Demo</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LogWrite</span><br>    &#123;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> DirectoryPathD = <span class="hljs-string">@&quot;D:\log\&quot;</span>;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WriteLog</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> filePath, <span class="hljs-built_in">string</span> content</span>)</span><br>        &#123;<br>            EnsureLogDirectoryExists();<br><br>            <span class="hljs-built_in">string</span> logFilePath = GetLogFilePath(filePath);<br>            WriteLogEntry(logFilePath, content);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WriteLogWithSQL</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> filePath, <span class="hljs-built_in">string</span> content, <span class="hljs-built_in">string</span> sql</span>)</span><br>        &#123;<br>            EnsureLogDirectoryExists();<br><br>            <span class="hljs-built_in">string</span> logFilePath = GetLogFilePath(filePath);<br>            WriteLogEntry(logFilePath, content, <span class="hljs-string">$&quot;Executed SQL: <span class="hljs-subst">&#123;sql&#125;</span>&quot;</span>);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WriteLogWithException</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> filePath, <span class="hljs-built_in">string</span> content, Exception ex</span>)</span><br>        &#123;<br>            EnsureLogDirectoryExists();<br><br>            <span class="hljs-built_in">string</span> logFilePath = GetLogFilePath(filePath);<br>            WriteLogEntry(logFilePath, content, <span class="hljs-string">$&quot;Exception Message: <span class="hljs-subst">&#123;ex.Message&#125;</span>\nStack Trace: <span class="hljs-subst">&#123;ex.StackTrace&#125;</span>&quot;</span>);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DeleteLog</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> folderPath</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">try</span><br>            &#123;<br>                DirectoryInfo dir = <span class="hljs-keyword">new</span> DirectoryInfo(folderPath);<br>                FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();<br><br>                <span class="hljs-keyword">foreach</span> (FileSystemInfo info <span class="hljs-keyword">in</span> fileinfo)<br>                &#123;<br>                    <span class="hljs-keyword">if</span> (info <span class="hljs-keyword">is</span> DirectoryInfo subdir)<br>                    &#123;<br>                        subdir.Delete(<span class="hljs-literal">true</span>);<br>                    &#125;<br>                    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (info.CreationTime &lt; DateTime.Now.AddDays(<span class="hljs-number">-7</span>))<br>                    &#123;<br>                        File.Delete(info.FullName);<br>                    &#125;<br>                &#125;<br>            &#125;<br>            <span class="hljs-keyword">catch</span> &#123; &#125;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">EnsureLogDirectoryExists</span>()</span><br>        &#123;<br>            <span class="hljs-keyword">if</span> (!Directory.Exists(DirectoryPathD))<br>            &#123;<br>                Directory.CreateDirectory(DirectoryPathD);<br>            &#125;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GetLogFilePath</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> filePath</span>)</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> Path.Combine(DirectoryPathD, <span class="hljs-string">$&quot;<span class="hljs-subst">&#123;DateTime.Now:yyyyMMdd&#125;</span>_<span class="hljs-subst">&#123;filePath&#125;</span>&quot;</span>);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WriteLogEntry</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> logFilePath, <span class="hljs-built_in">string</span> content, <span class="hljs-built_in">string</span> additionalInfo = <span class="hljs-string">&quot;&quot;</span></span>)</span><br>        &#123;<br>            <span class="hljs-built_in">int</span> logNumber = GetNextLogNumber(logFilePath);<br><br>            <span class="hljs-keyword">using</span> (FileStream aFile = <span class="hljs-keyword">new</span> FileStream(logFilePath, FileMode.Append))<br>            <span class="hljs-keyword">using</span> (StreamWriter sw = <span class="hljs-keyword">new</span> StreamWriter(aFile, System.Text.Encoding.UTF8))<br>            &#123;<br>                sw.WriteLine(<span class="hljs-string">$&quot;[<span class="hljs-subst">&#123;logNumber&#125;</span>] <span class="hljs-subst">&#123;DateTime.Now&#125;</span>;<span class="hljs-subst">&#123;content&#125;</span>&quot;</span>);<br>                <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">string</span>.IsNullOrEmpty(additionalInfo))<br>                &#123;<br>                    sw.WriteLine(additionalInfo);<br>                &#125;<br>                sw.WriteLine();<br>            &#125;<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-built_in">int</span> <span class="hljs-title">GetNextLogNumber</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> logFilePath</span>)</span><br>        &#123;<br>            <span class="hljs-built_in">int</span> logNumber = <span class="hljs-number">1</span>;<br><br>            <span class="hljs-keyword">if</span> (File.Exists(logFilePath))<br>            &#123;<br>                <span class="hljs-built_in">string</span>[] lines = File.ReadAllLines(logFilePath);<br>                <span class="hljs-keyword">foreach</span> (<span class="hljs-built_in">string</span> line <span class="hljs-keyword">in</span> lines)<br>                &#123;<br>                    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">string</span>.IsNullOrWhiteSpace(line) &amp;&amp; Regex.IsMatch(line, <span class="hljs-string">@&quot;^\[(\d+)\]&quot;</span>))<br>                    &#123;<br>                        <span class="hljs-built_in">int</span> logIndex = <span class="hljs-built_in">int</span>.Parse(Regex.Match(line, <span class="hljs-string">@&quot;^\[(\d+)\]&quot;</span>).Groups[<span class="hljs-number">1</span>].Value);<br>                        logNumber = logIndex + <span class="hljs-number">1</span>;<br>                    &#125;<br>                &#125;<br>            &#125;<br><br>            <span class="hljs-keyword">return</span> logNumber;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>当我们深入了解上述代码中每个方法的实现时，可以更清楚地理解其工作原理和实现方式：</p><ol><li><p><code>WriteLog</code>：</p><ul><li>首先，方法调用 <code>EnsureLogDirectoryExists</code> 以确保日志文件夹存在，若不存在则创建。</li><li>然后，通过调用 <code>GetLogFilePath</code> 构建完整的日志文件路径，包括当前日期作为前缀。</li><li>最后，调用 <code>WriteLogEntry</code> 方法，将传递的日志内容写入到指定的日志文件中。</li></ul></li><li><p><code>WriteLogWithSQL</code>：</p><ul><li>与 <code>WriteLog</code> 类似，先确保日志文件夹存在并构建日志文件路径。</li><li>调用 <code>WriteLogEntry</code> 方法，将传递的日志内容和附加信息（执行的 SQL 语句）一同写入到日志文件中。</li></ul></li><li><p><code>WriteLogWithException</code>：</p><ul><li>同样，确保日志文件夹存在并构建日志文件路径。</li><li>调用 <code>WriteLogEntry</code> 方法，将传递的日志内容和附加信息（异常消息和堆栈跟踪）一同写入到日志文件中。</li></ul></li><li><p><code>DeleteLog</code>：</p><ul><li>方法首先尝试获取指定文件夹中的所有文件和子文件夹。</li><li>然后，对于每个文件和子文件夹，检查其创建时间。如果是文件夹，则递归删除；如果是文件且创建时间早于7天前，则删除文件。</li><li>这样，可以确保过期的日志文件被及时清理，避免过多占用磁盘空间。</li></ul></li><li><p><code>EnsureLogDirectoryExists</code>：</p><ul><li>这个方法检查日志文件夹路径是否存在，如果不存在则调用 <code>Directory.CreateDirectory</code> 创建文件夹。</li></ul></li><li><p><code>GetLogFilePath</code>：</p><ul><li>方法将当前日期格式化为字符串，并将其与传递的文件路径结合，形成完整的日志文件路径。</li></ul></li><li><p><code>WriteLogEntry</code>：</p><ul><li>该方法将日志内容写入日志文件。</li><li>首先，获取下一个可用的日志编号，调用 <code>GetNextLogNumber</code> 。</li><li>然后，使用文件流 <code>FileStream</code> 和写入器 <code>StreamWriter</code> 打开指定的日志文件，使用 UTF-8 编码。</li><li>将日志内容和附加信息（如果提供）写入到文件中，确保写入操作的原子性。</li></ul></li><li><p><code>GetNextLogNumber</code>：</p><ul><li>方法读取已有的日志文件内容，分析每行中的日志编号，找到最大的编号。</li><li>在找到最大编号后，将其加一作为下一个可用的日志编号，确保日志编号的连续性和唯一性。</li></ul></li></ol><p>通过这些方法的具体实现，<code>LogWrite</code> 类提供了一个可靠且易于使用的日志记录工具，帮助开发人员有效地管理和记录应用程序的各种信息，从而更好地进行故障排除和性能优化。</p><h3 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h3><p>下面是一个更详细的使用示例，展示了如何使用<code>LogWrite</code>类来记录日志：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> System;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">Demo</span><br>&#123;<br>    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-built_in">string</span>[] args</span>)</span><br>        &#123;<br>            LogWrite logger = <span class="hljs-keyword">new</span> LogWrite();<br><br>            <span class="hljs-keyword">try</span><br>            &#123;<br>                <span class="hljs-comment">// 模拟执行SQL语句</span><br>                <span class="hljs-built_in">string</span> sql = <span class="hljs-string">&quot;SELECT * FROM Customers&quot;</span>;<br>                <span class="hljs-comment">// 模拟异常</span><br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">&quot;An error occurred!&quot;</span>);<br><br>                logger.WriteLogWithSQL(<span class="hljs-string">&quot;app.log&quot;</span>, <span class="hljs-string">&quot;Application started&quot;</span>, sql);<br>            &#125;<br>            <span class="hljs-keyword">catch</span> (Exception ex)<br>            &#123;<br>                logger.WriteLogWithException(<span class="hljs-string">&quot;error.log&quot;</span>, <span class="hljs-string">&quot;An error occurred&quot;</span>, ex);<br>            &#125;<br><br>            logger.DeleteLog(<span class="hljs-string">@&quot;D:\log\&quot;</span>); <span class="hljs-comment">// 清理过期日志</span><br><br>            Console.WriteLine(<span class="hljs-string">&quot;Log entries recorded.&quot;</span>);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>通过详细介绍这个名为 <code>LogWrite</code> 的类库，我们呈现了一个灵活、可靠且便捷的日志记录工具，它可以协助开发人员轻松地满足各种日志记录需求。不论是对常规信息、SQL 语句或异常情况的记录，这个类库都提供了简便而可靠的方法。此外，它还具备自动创建日志文件夹和清理过期日志的功能，确保了日志记录的高效管理。在开发和维护过程中，这样的日志记录工具将成为宝贵的助手，帮助我们更好地理解和优化应用程序的运行情况。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在软件开发中，日志记录是一项至关重要的任务，它可以帮助我们跟踪应用程序的状态、故障排除和性能优化。在本篇博客中，我们将深入介绍一个用于日志记录的 C# 类库，展示其如何实现灵活、可靠且易于使用的特性。&lt;/p&gt;
&lt;h3 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>在 C# 中创建 Excel 文件</title>
    <link href="http://www.loquy.cn/posts/29482ab7.html"/>
    <id>http://www.loquy.cn/posts/29482ab7.html</id>
    <published>2023-07-20T06:01:35.000Z</published>
    <updated>2023-07-20T06:01:35.000Z</updated>
    
    <content type="html"><![CDATA[<p>在本篇博客中，我们将介绍如何使用 EPPlus 库在 C# 中创建 Excel 文件。EPPlus 是一个用于操作 Excel 文件的强大开源库，它支持 .NET Framework 和 .NET Core 平台。</p><h2 id="安装-EPPlus"><a href="#安装-EPPlus" class="headerlink" title="安装 EPPlus"></a>安装 EPPlus</h2><p>首先，我们需要安装 EPPlus 库。你可以使用 NuGet 包管理器来安装 EPPlus。以下是安装过程：</p><ol><li>打开 Visual Studio 项目。</li><li>在解决方案资源管理器中，右键单击项目，然后选择“管理 NuGet 程序包”。</li><li>在 NuGet 程序包管理器中，搜索“EPPlus”。</li><li>选择 EPPlus，并点击“安装”按钮完成安装过程。</li></ol><h2 id="导出数据到-Excel"><a href="#导出数据到-Excel" class="headerlink" title="导出数据到 Excel"></a>导出数据到 Excel</h2><p>首先，我们需要对 <code>ExcelUtils</code> 类进行扩展，以便它能够接受不同类型的数据源。为实现这个目标，我们将使用泛型方法，使得该方法可以处理各种类型的数据源。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> OfficeOpenXml;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Collections.Generic;<br><span class="hljs-keyword">using</span> System.IO;<br><span class="hljs-keyword">using</span> System.Windows.Forms;<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title">DEMO</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ExcelUtils</span><br>    &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> <span class="hljs-title">DataGridViewToExcel</span>(<span class="hljs-params">DataGridView dataGridView, <span class="hljs-built_in">string</span> filePath, <span class="hljs-built_in">string</span> sheetName</span>)</span><br>        &#123;<br>            <span class="hljs-comment">// 导出表头</span><br>            List&lt;<span class="hljs-built_in">string</span>&gt; headers = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-built_in">string</span>&gt;();<br>            <span class="hljs-keyword">foreach</span> (DataGridViewColumn column <span class="hljs-keyword">in</span> dataGridView.Columns)<br>            &#123;<br>                headers.Add(column.HeaderText);<br>            &#125;<br><br>            <span class="hljs-comment">// 导出数据</span><br>            List&lt;List&lt;<span class="hljs-built_in">object</span>&gt;&gt; data = <span class="hljs-keyword">new</span> List&lt;List&lt;<span class="hljs-built_in">object</span>&gt;&gt;();<br>            <span class="hljs-keyword">foreach</span> (DataGridViewRow row <span class="hljs-keyword">in</span> dataGridView.Rows)<br>            &#123;<br>                List&lt;<span class="hljs-built_in">object</span>&gt; rowData = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-built_in">object</span>&gt;();<br>                <span class="hljs-keyword">foreach</span> (DataGridViewCell cell <span class="hljs-keyword">in</span> row.Cells)<br>                &#123;<br>                    rowData.Add(cell.Value);<br>                &#125;<br>                data.Add(rowData);<br>            &#125;<br><br>            <span class="hljs-comment">// 调用通用导出方法</span><br>            <span class="hljs-keyword">return</span> ExportToExcel(filePath, sheetName, headers, data);<br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> <span class="hljs-title">ExportToExcel</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-built_in">string</span> filePath, <span class="hljs-built_in">string</span> sheetName, List&lt;<span class="hljs-built_in">string</span>&gt; headers, List&lt;List&lt;T&gt;&gt; data</span>)</span><br>        &#123;<br>            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;<br>            <span class="hljs-keyword">try</span><br>            &#123;<br>                <span class="hljs-keyword">using</span> (ExcelPackage excelPackage = <span class="hljs-keyword">new</span> ExcelPackage())<br>                &#123;<br>                    ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add(sheetName);<br><br>                    <span class="hljs-comment">// 导出表头</span><br>                    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i &lt; headers.Count; i++)<br>                    &#123;<br>                        worksheet.Cells[<span class="hljs-number">1</span>, i + <span class="hljs-number">1</span>].Value = headers[i];<br>                    &#125;<br><br>                    <span class="hljs-comment">// 导出数据</span><br>                    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i &lt; data.Count; i++)<br>                    &#123;<br>                        <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> j = <span class="hljs-number">0</span>; j &lt; data[i].Count; j++)<br>                        &#123;<br>                            worksheet.Cells[i + <span class="hljs-number">2</span>, j + <span class="hljs-number">1</span>].Value = data[i][j];<br>                        &#125;<br>                    &#125;<br><br>                    <span class="hljs-comment">// 保存 Excel 文件</span><br>                    FileInfo excelFile = <span class="hljs-keyword">new</span> FileInfo(filePath);<br>                    excelPackage.SaveAs(excelFile);<br>                &#125;<br><br>                <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;导出完成！&quot;</span>;<br>            &#125;<br>            <span class="hljs-keyword">catch</span> (Exception ex)<br>            &#123;<br>                <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;导出发生错误：&quot;</span> + ex.Message;<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>现在，<code>ExcelUtils</code> 类有两个方法：</p><ol><li><code>DataGridViewToExcel</code> 方法：用于导出 DataGridView 的数据到 Excel 文件。</li><li><code>ExportToExcel</code> 泛型方法：可以处理各种类型的数据源，包括二维列表、DataTable 等。</li></ol><ul><li><strong>使用示例：</strong><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-comment">// 示例1：使用 DataGridView 数据源</span><br><span class="hljs-built_in">string</span> filePath1 = <span class="hljs-string">&quot;C:\\Example\\Sample1.xlsx&quot;</span>;<br><span class="hljs-built_in">string</span> sheetName1 = <span class="hljs-string">&quot;Sheet1&quot;</span>;<br><span class="hljs-built_in">string</span> result1 = ExcelUtils.ExportToExcel(dataGridView1, filePath1, sheetName1);<br>Console.WriteLine(result1);<br><br><span class="hljs-comment">// 示例2：使用二维列表数据源</span><br><span class="hljs-built_in">string</span> filePath2 = <span class="hljs-string">&quot;C:\\Example\\Sample2.xlsx&quot;</span>;<br><span class="hljs-built_in">string</span> sheetName2 = <span class="hljs-string">&quot;Sheet2&quot;</span>;<br>List&lt;<span class="hljs-built_in">string</span>&gt; headers = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-built_in">string</span>&gt; &#123; <span class="hljs-string">&quot;Name&quot;</span>, <span class="hljs-string">&quot;Age&quot;</span>, <span class="hljs-string">&quot;City&quot;</span> &#125;;<br>List&lt;List&lt;<span class="hljs-built_in">object</span>&gt;&gt; data = <span class="hljs-keyword">new</span> List&lt;List&lt;<span class="hljs-built_in">object</span>&gt;&gt;<br>&#123;<br>    <span class="hljs-keyword">new</span> List&lt;<span class="hljs-built_in">object</span>&gt; &#123; <span class="hljs-string">&quot;John&quot;</span>, <span class="hljs-number">30</span>, <span class="hljs-string">&quot;New York&quot;</span> &#125;,<br>    <span class="hljs-keyword">new</span> List&lt;<span class="hljs-built_in">object</span>&gt; &#123; <span class="hljs-string">&quot;Alice&quot;</span>, <span class="hljs-number">25</span>, <span class="hljs-string">&quot;Los Angeles&quot;</span> &#125;,<br>    <span class="hljs-keyword">new</span> List&lt;<span class="hljs-built_in">object</span>&gt; &#123; <span class="hljs-string">&quot;Bob&quot;</span>, <span class="hljs-number">35</span>, <span class="hljs-string">&quot;Chicago&quot;</span> &#125;<br>&#125;;<br><span class="hljs-built_in">string</span> result2 = ExcelUtils.ExportToExcel(filePath2, sheetName2, headers, data);<br>Console.WriteLine(result2);<br><br></code></pre></td></tr></table></figure></li></ul><p>现在你可以根据数据源的类型来选择适当的导出方法，<code>DataGridViewToExcel</code> 用于 DataGridView 数据，而 <code>ExportToExcel</code> 用于其他类型的数据源。这样，你可以方便地将各种数据导出到 Excel 文件中。</p><p>希望这篇博客对你有所帮助！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在本篇博客中，我们将介绍如何使用 EPPlus 库在 C# 中创建 Excel 文件。EPPlus 是一个用于操作 Excel 文件的强大开源库，它支持 .NET Framework 和 .NET Core 平台。&lt;/p&gt;
&lt;h2 id=&quot;安装-EPPlus&quot;&gt;&lt;a hre</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>WinForms 中实现自动关闭的 MessageBox</title>
    <link href="http://www.loquy.cn/posts/1883a8de.html"/>
    <id>http://www.loquy.cn/posts/1883a8de.html</id>
    <published>2023-07-13T07:42:03.000Z</published>
    <updated>2023-12-22T06:37:30.973Z</updated>
    
    <content type="html"><![CDATA[<p>在许多软件应用程序中，经常需要显示一段时间后自动关闭的消息框。这种功能可以为用户提供及时的反馈，同时又不会干扰用户的操作。本文将介绍一个使用 C# 编写的自动关闭消息框的代码示例，并详细解释其实现原理。</p><h2 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ShowMessageBoxInThread</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> message, <span class="hljs-built_in">int</span> time = <span class="hljs-number">1000</span>, <span class="hljs-built_in">string</span> title = <span class="hljs-string">&quot;提示&quot;</span></span>)</span><br>&#123;<br>    <span class="hljs-keyword">await</span> Task.Run(() =&gt; AutoClosingMessageBox.Show(message, title, time));<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AutoClosingMessageBox</span><br>&#123;<br>    System.Threading.Timer _timeoutTimer;<br>    <span class="hljs-built_in">string</span> _caption;<br><br>    AutoClosingMessageBox(<span class="hljs-built_in">string</span> text, <span class="hljs-built_in">string</span> caption, <span class="hljs-built_in">int</span> timeout)<br>    &#123;<br>        _caption = caption;<br>        _timeoutTimer = <span class="hljs-keyword">new</span> System.Threading.Timer(OnTimerElapsed,<br>            <span class="hljs-literal">null</span>, timeout, System.Threading.Timeout.Infinite);<br>        <span class="hljs-keyword">using</span> (_timeoutTimer)<br>            MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Information);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Show</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> text, <span class="hljs-built_in">string</span> caption, <span class="hljs-built_in">int</span> timeout</span>)</span><br>    &#123;<br>        <span class="hljs-keyword">new</span> AutoClosingMessageBox(text, caption, timeout);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">OnTimerElapsed</span>(<span class="hljs-params"><span class="hljs-built_in">object</span> state</span>)</span><br>    &#123;<br>        IntPtr mbWnd = FindWindow(<span class="hljs-string">&quot;#32770&quot;</span>, _caption); <span class="hljs-comment">// lpClassName is #32770 for MessageBox</span><br>        <span class="hljs-keyword">if</span> (mbWnd != IntPtr.Zero)<br>            SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);<br>        _timeoutTimer.Dispose();<br>    &#125;<br><br>    <span class="hljs-keyword">const</span> <span class="hljs-built_in">int</span> WM_CLOSE = <span class="hljs-number">0x0010</span>;<br>    [<span class="hljs-meta">System.Runtime.InteropServices.DllImport(<span class="hljs-string">&quot;user32.dll&quot;</span>, SetLastError = true)</span>]<br>    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">extern</span> IntPtr <span class="hljs-title">FindWindow</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> lpClassName, <span class="hljs-built_in">string</span> lpWindowName</span>)</span>;<br>    [<span class="hljs-meta">System.Runtime.InteropServices.DllImport(<span class="hljs-string">&quot;user32.dll&quot;</span>, CharSet = System.Runtime.InteropServices.CharSet.Auto)</span>]<br>    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">extern</span> IntPtr <span class="hljs-title">SendMessage</span>(<span class="hljs-params">IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam</span>)</span>;<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h2><p>让我们逐步解释上述代码的实现原理。</p><h3 id="ShowMessageBoxInThread-方法"><a href="#ShowMessageBoxInThread-方法" class="headerlink" title="ShowMessageBoxInThread 方法"></a>ShowMessageBoxInThread 方法</h3><p>首先，我们有一个私有的异步方法<code>ShowMessageBoxInThread</code>，它接受三个参数：<code>message</code>表示要显示的消息内容，<code>time</code>表示消息框显示的时间（默认为1秒），<code>title</code>表示消息框的标题（默认为”提示”）。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ShowMessageBoxInThread</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> message, <span class="hljs-built_in">int</span> time = <span class="hljs-number">1000</span>, <span class="hljs-built_in">string</span> title = <span class="hljs-string">&quot;提示&quot;</span></span>)</span><br>&#123;<br>    <span class="hljs-keyword">await</span> Task.Run(() =&gt; AutoClosingMessageBox.Show(message, title, time));<br>&#125;<br></code></pre></td></tr></table></figure><p>在方法内部，我们使用<code>Task.Run</code>创建一个异步任务，并调用<code>AutoClosingMessageBox.Show</code>方法。通过将消息内容、标题和显示时间传递给<code>Show</code>方法，我们将显示一个自动关闭的消息框。</p><h3 id="AutoClosingMessageBox-类"><a href="#AutoClosingMessageBox-类" class="headerlink" title="AutoClosingMessageBox 类"></a>AutoClosingMessageBox 类</h3><p><code>AutoClosingMessageBox</code>类是实现自动关闭消息框的核心部分。</p><p>首先，它包含了一个私有字段<code>_timeoutTimer</code>和一个表示消息框标题的字段<code>_caption</code>。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AutoClosingMessageBox</span><br>&#123;<br>    System.Threading.Timer _timeoutTimer;<br>    <span class="hljs-built_in">string</span> _caption;<br>    <span class="hljs-comment">// ...</span><br>&#125;<br></code></pre></td></tr></table></figure><p>构造函数<code>AutoClosingMessageBox</code>接受消息内容、标题和超时时间作为参数。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs csharp">AutoClosingMessageBox(<span class="hljs-built_in">string</span> text, <span class="hljs-built_in">string</span> caption, <span class="hljs-built_in">int</span> timeout)<br>&#123;<br>    _caption = caption;<br>    _timeoutTimer = <span class="hljs-keyword">new</span> System.Threading.Timer(OnTimerElapsed,<br>        <span class="hljs-literal">null</span>, timeout, System.Threading.Timeout.Infinite);<br>    <span class="hljs-keyword">using</span> (_timeoutTimer)<br>        MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Information);<br>&#125;<br></code></pre></td></tr></table></figure><p>在构造函数内部，首先设置了一个计时器<code>_timeoutTimer</code>，它在指定的超时时间后触发回调函数<code>OnTimerElapsed</code>。计时器的工作是在超时后关闭消息框。</p><p>当初始化定时器时，我们使用 <code>new System.Threading.Timer(OnTimerElapsed, null, timeout, System.Threading.Timeout.Infinite)</code> 这段代码。它创建了一个新的 <code>System.Threading.Timer</code> 实例，并设置了相关参数：</p><ul><li><code>OnTimerElapsed</code> 是定时器触发时要执行的回调方法。</li><li><code>null</code> 表示传递给回调方法的状态对象，这里我们不需要传递额外的状态信息。</li><li><code>timeout</code> 表示定时器的超时时间，即经过多少毫秒后触发回调方法。</li><li><code>System.Threading.Timeout.Infinite</code> 表示定时器只触发一次，并不会重复。</li></ul><p><code>using</code> 语句是一种资源管理语句，用于确保在使用完毕后正确释放资源。在这里，我们使用 <code>using</code> 语句来管理 <code>_timeoutTimer</code> 对象的生命周期。当执行到 <code>using</code> 语句的末尾时，会自动调用 <code>_timeoutTimer.Dispose()</code> 方法来释放定时器资源。</p><p>接下来，使用<code>MessageBox.Show</code>方法显示消息框，并传递消息内容、标题以及信息图标。</p><h3 id="OnTimerElapsed-方法"><a href="#OnTimerElapsed-方法" class="headerlink" title="OnTimerElapsed 方法"></a>OnTimerElapsed 方法</h3><p><code>OnTimerElapsed</code>方法是计时器回调函数，它在超时时被调用。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">OnTimerElapsed</span>(<span class="hljs-params"><span class="hljs-built_in">object</span> state</span>)</span><br>&#123;<br>    IntPtr mbWnd = FindWindow(<span class="hljs-string">&quot;#32770&quot;</span>, _caption); <span class="hljs-comment">// lpClassName is #32770 for MessageBox</span><br>    <span class="hljs-keyword">if</span> (mbWnd != IntPtr.Zero)<br>        SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);<br>    _timeoutTimer.Dispose();<br>&#125;<br></code></pre></td></tr></table></figure><p>在<code>OnTimerElapsed</code>方法中，首先通过<code>FindWindow</code>函数查找具有指定标题的消息框的句柄。如果找到了消息框的句柄，就使用<code>SendMessage</code>函数发送关闭消息给消息框，即通过向消息框发送<code>WM_CLOSE</code>消息来关闭它。最后，我们释放计时器资源。</p><h3 id="DllImport-特性"><a href="#DllImport-特性" class="headerlink" title="DllImport 特性"></a>DllImport 特性</h3><p>代码中还使用了 DllImport 特性，用于声明<code>FindWindow</code>和<code>SendMessage</code>方法，以便在 C# 代码中使用这些来自 user32.dll 的本机函数。</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">const</span> <span class="hljs-built_in">int</span> WM_CLOSE = <span class="hljs-number">0x0010</span>;<br>[<span class="hljs-meta">System.Runtime.InteropServices.DllImport(<span class="hljs-string">&quot;user32.dll&quot;</span>, SetLastError = true)</span>]<br><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">extern</span> IntPtr <span class="hljs-title">FindWindow</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> lpClassName, <span class="hljs-built_in">string</span> lpWindowName</span>)</span>;<br>[<span class="hljs-meta">System.Runtime.InteropServices.DllImport(<span class="hljs-string">&quot;user32.dll&quot;</span>, CharSet = System.Runtime.InteropServices.CharSet.Auto)</span>]<br><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">extern</span> IntPtr <span class="hljs-title">SendMessage</span>(<span class="hljs-params">IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam</span>)</span>;<br></code></pre></td></tr></table></figure><p>这些特性允许我们直接调用 Windows API 函数，以实现与操作系统交互的功能。</p><ul><li><code>const int WM_CLOSE = 0x0010;</code> 定义了一个常量 <code>WM_CLOSE</code>，它代表了关闭窗口的消息代码。</li><li><code>[System.Runtime.InteropServices.DllImport(&quot;user32.dll&quot;, SetLastError = true)]</code> 是一个 <code>DllImport</code> 特性，用于指示在 <code>user32.dll</code> 库中查找并导入函数。<code>SetLastError</code> 参数设置为 <code>true</code>，以便在函数调用失败时记录错误状态。</li><li><code>static extern IntPtr FindWindow(string lpClassName, string lpWindowName);</code> 声明了一个名为 <code>FindWindow</code> 的本机函数，它在 <code>user32.dll</code> 中查找具有指定类名和窗口名的顶层窗口。它返回找到的窗口的句柄。</li><li><code>static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);</code> 声明了一个名为 <code>SendMessage</code> 的本机函数，它向指定的窗口发送指定的消息。<code>hWnd</code> 参数是窗口的句柄，<code>Msg</code> 参数是要发送的消息代码，<code>wParam</code> 和 <code>lParam</code> 参数是消息的参数。</li></ul><p>这些代码用于在 C# 中与 Windows API 进行交互。通过 <code>FindWindow</code> 函数找到指定标题的窗口句柄，并使用 <code>SendMessage</code> 函数向该窗口发送关闭消息。这样可以实现在定时器回调方法中自动关闭消息框的功能。</p><h2 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h2><p>通过使用以上的代码，我们可以在应用程序中使用<code>ShowMessageBoxInThread</code>方法来显示一个自动关闭的消息框。例如：</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs csharp">ShowMessageBoxInThread(<span class="hljs-string">&quot;操作已完成！&quot;</span>, <span class="hljs-number">2000</span>, <span class="hljs-string">&quot;成功&quot;</span>);<br></code></pre></td></tr></table></figure><p>以上代码将在一个新的线程中显示一个带有”成功”标题的消息框，显示内容为”操作已完成！”，并在2秒后自动关闭。</p><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://stackoverflow.com/questions/14522540/close-a-messagebox-after-several-seconds">Close a MessageBox after several seconds</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在许多软件应用程序中，经常需要显示一段时间后自动关闭的消息框。这种功能可以为用户提供及时的反馈，同时又不会干扰用户的操作。本文将介绍一个使用 C# 编写的自动关闭消息框的代码示例，并详细解释其实现原理。&lt;/p&gt;
&lt;h2 id=&quot;代码示例&quot;&gt;&lt;a href=&quot;#代码示例&quot; c</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
    <category term="WinForms" scheme="http://www.loquy.cn/tags/WinForms/"/>
    
  </entry>
  
  <entry>
    <title>C# 中的 JSON 数据存储、读取和合并操作</title>
    <link href="http://www.loquy.cn/posts/6f32793d.html"/>
    <id>http://www.loquy.cn/posts/6f32793d.html</id>
    <published>2023-07-07T01:43:53.000Z</published>
    <updated>2023-07-07T01:43:53.000Z</updated>
    
    <content type="html"><![CDATA[<p>在博客中，我将介绍一个名为<code>JsonFileManager</code>的类，该类用于管理数据的保存和读取操作，并提供了一些数据合并的方法。下面是该类的代码及其功能的详细说明。</p><h2 id="引用和命名空间"><a href="#引用和命名空间" class="headerlink" title="引用和命名空间"></a>引用和命名空间</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">using</span> Newtonsoft.Json;<br><span class="hljs-keyword">using</span> System;<br><span class="hljs-keyword">using</span> System.Collections.Generic;<br><span class="hljs-keyword">using</span> System.IO;<br></code></pre></td></tr></table></figure><p>上述代码段中的<code>using</code>语句用于引入所需的命名空间，以便在代码中使用相关的类型和方法。</p><h2 id="命名空间"><a href="#命名空间" class="headerlink" title="命名空间"></a>命名空间</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Demo</span><br>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">JsonFileManager</span><br>    &#123;<br>        <span class="hljs-comment">// ...</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>在该命名空间中，定义了一个名为<code>JsonFileManager</code>的静态类，用于提供数据保存和读取的功能。</p><h2 id="常量和文件路径"><a href="#常量和文件路径" class="headerlink" title="常量和文件路径"></a>常量和文件路径</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> BACKUP_DIRECTORY = <span class="hljs-string">@&quot;C:\json_backup\&quot;</span>;<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> INBOUND_FILE_NAME = <span class="hljs-string">&quot;Inbound.json&quot;</span>;<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> OUTBOUND_FILE_NAME = <span class="hljs-string">&quot;OutBound.json&quot;</span>;<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> CUSTOMER_FILE_NAME = <span class="hljs-string">&quot;Customer.json&quot;</span>;<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> MATERIAL_FILE_NAME = <span class="hljs-string">&quot;Material.json&quot;</span>;<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> SUPPLIER_FILE_NAME = <span class="hljs-string">&quot;Supplier.json&quot;</span>;<br></code></pre></td></tr></table></figure><p>这些常量定义了备份目录的路径和各个数据文件的文件名。</p><h2 id="SaveData-方法"><a href="#SaveData-方法" class="headerlink" title="SaveData 方法"></a>SaveData<T> 方法</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SaveData</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">List&lt;T&gt; data, <span class="hljs-built_in">string</span> filename</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 检查备份目录是否存在，如果不存在则创建</span><br>    <span class="hljs-keyword">if</span> (!Directory.Exists(BACKUP_DIRECTORY))<br>        Directory.CreateDirectory(BACKUP_DIRECTORY);<br><br>    <span class="hljs-comment">// 生成文件路径</span><br>    <span class="hljs-built_in">string</span> filePath = Path.Combine(BACKUP_DIRECTORY, filename);<br><br>    <span class="hljs-comment">// 读取已保存的数据</span><br>    List&lt;T&gt; existingData = ReadData&lt;T&gt;(filename);<br><br>    <span class="hljs-comment">// 合并数据，去除重复项</span><br>    List&lt;T&gt; newData = MergeData(existingData, data);<br><br>    <span class="hljs-comment">// 将数据序列化为 JSON 字符串</span><br>    <span class="hljs-built_in">string</span> json = JsonConvert.SerializeObject(newData, Formatting.Indented);<br><br>    <span class="hljs-comment">// 保存 JSON 字符串到文件</span><br>    File.WriteAllText(filePath, json);<br>&#125;<br></code></pre></td></tr></table></figure><p>该方法用于保存数据到指定的文件。它接收一个泛型参数<code>T</code>表示数据类型，一个<code>List&lt;T&gt;</code>类型的<code>data</code>参数表示要保存的数据列表，以及一个<code>string</code>类型的<code>filename</code>参数表示文件名。方法的实现逻辑如下：</p><ol><li>检查备份目录是否存在，如果不存在则创建备份目录。</li><li>生成文件路径。</li><li>调用<code>ReadData&lt;T&gt;</code>方法读取已保存的数据。</li><li>调用<code>MergeData</code>方法合并已保存的数据和新数据，去除重复项。</li><li>使用<code>JsonConvert.SerializeObject</code>方法将数据序列化为 JSON 字符串。</li><li>调用<code>File.WriteAllText</code>方法将 JSON 字符串写入文件。</li></ol><h2 id="ReadData-方法"><a href="#ReadData-方法" class="headerlink" title="ReadData 方法"></a>ReadData<T> 方法</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">ReadData</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-built_in">string</span> filename</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 生成文件路径</span><br>    <span class="hljs-built_in">string</span> filePath = Path.Combine(BACKUP_DIRECTORY, filename);<br><br>    <span class="hljs-comment">// 检查文件是否存在</span><br>    <span class="hljs-keyword">if</span> (!File.Exists(filePath))<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> List&lt;T&gt;();<br><br>    <span class="hljs-comment">// 读取文件内容</span><br>    <span class="hljs-built_in">string</span> json = File.ReadAllText(filePath);<br><br>    <span class="hljs-comment">// 反序列化 JSON 字符串为数据对象</span><br>    List&lt;T&gt; data = JsonConvert.DeserializeObject&lt;List&lt;T&gt;&gt;(json);<br><br>    <span class="hljs-keyword">return</span> data ?? <span class="hljs-keyword">new</span> List&lt;T&gt;();<br>&#125;<br></code></pre></td></tr></table></figure><p>该方法用于读取指定文件中的数据，并以<code>List&lt;T&gt;</code>类型的列表形式返回。它接收一个<code>string</code>类型的<code>filename</code>参数表示要读取的文件名。方法的实现逻辑如下：</p><ol><li>生成文件路径。</li><li>检查文件是否存在，如果文件不存在则返回空的数据列表。</li><li>读取文件内容。</li><li>使用<code>JsonConvert.DeserializeObject</code>方法将 JSON 字符串反序列化为数据对象。</li><li>返回反序列化后的数据列表。</li></ol><h2 id="MergeData-方法"><a href="#MergeData-方法" class="headerlink" title="MergeData 方法"></a>MergeData<T> 方法</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">MergeData</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">List&lt;T&gt; existingData, List&lt;T&gt; newData</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 获取属性名用于去重判断</span><br>    <span class="hljs-built_in">string</span> propertyName = GetPropertyName&lt;T&gt;();<br><br>    <span class="hljs-comment">// 去除重复项</span><br>    HashSet&lt;<span class="hljs-built_in">string</span>&gt; existingSet = <span class="hljs-keyword">new</span> HashSet&lt;<span class="hljs-built_in">string</span>&gt;();<br>    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> item <span class="hljs-keyword">in</span> existingData)<br>    &#123;<br>        <span class="hljs-keyword">var</span> propertyValue = GetPropertyValue(item, propertyName);<br>        <span class="hljs-keyword">if</span> (propertyValue != <span class="hljs-literal">null</span>)<br>        &#123;<br>            existingSet.Add(propertyValue.ToString());<br>        &#125;<br>    &#125;<br><br>    List&lt;T&gt; mergedData = <span class="hljs-keyword">new</span> List&lt;T&gt;(existingData);<br>    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> item <span class="hljs-keyword">in</span> newData)<br>    &#123;<br>        <span class="hljs-keyword">var</span> propertyValue = GetPropertyValue(item, propertyName);<br>        <span class="hljs-keyword">if</span> (propertyValue != <span class="hljs-literal">null</span> &amp;&amp; !existingSet.Contains(propertyValue.ToString()))<br>        &#123;<br>            mergedData.Add(item);<br>            existingSet.Add(propertyValue.ToString());<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">return</span> mergedData;<br>&#125;<br></code></pre></td></tr></table></figure><p>该方法用于合并已保存的数据和新数据，并去除重复项。它接收两个<code>List&lt;T&gt;</code>类型的参数<code>existingData</code>和<code>newData</code>，表示已保存的数据和新数据。方法的实现逻辑如下：</p><ol><li>获取用于去重判断的属性名，调用<code>GetPropertyName&lt;T&gt;</code>方法获取属性名。</li><li>创建一个<code>HashSet&lt;string&gt;</code>类型的集合<code>existingSet</code>，用于存储已保存数据中的属性值。</li><li>遍历已保存数据列表<code>existingData</code>，获取每个数据项的属性值，并将属性值转换为字符串类型后添加到<code>existingSet</code>集合中。</li><li>创建一个新的数据列表<code>mergedData</code>，初始值为已保存的数据列表<code>existingData</code>的副本。</li><li>遍历新数据列表<code>newData</code>，获取每个数据项的属性值，并判断属性值是否为空以及<code>existingSet</code>集合是否包含该属性值的字符串形式。</li><li>如果属性值不为空且<code>existingSet</code>集合中不包含该属性值的字符串形式，则将数据项添加到<code>mergedData</code>列表中，并将属性值的字符串形式添加到<code>existingSet</code>集合中。</li><li>返回合并后的数据列表<code>mergedData</code>。</li></ol><h2 id="MergeDataWithLocal-方法"><a href="#MergeDataWithLocal-方法" class="headerlink" title="MergeDataWithLocal 方法"></a>MergeDataWithLocal<T> 方法</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">MergeDataWithLocal</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">List&lt;T&gt; newData, <span class="hljs-built_in">string</span> filename</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 读取本地的数据 </span><br>    List&lt;T&gt; existingData= ReadData&lt;T&gt;(filename);<br><br>    <span class="hljs-comment">// 获取属性名用于查找本地数据</span><br>    <span class="hljs-built_in">string</span> propertyName = GetPropertyName&lt;T&gt;();<br><br>    <span class="hljs-comment">// 创建字典映射</span><br>    Dictionary&lt;<span class="hljs-built_in">string</span>, T&gt; existingDataMap = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-built_in">string</span>, T&gt;();<br><br>    <span class="hljs-comment">// 填充字典映射</span><br>    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> item <span class="hljs-keyword">in</span> existingData)<br>    &#123;<br>        <span class="hljs-keyword">var</span> propertyValue = GetPropertyValue(item, propertyName);<br>        <span class="hljs-keyword">if</span> (propertyValue != <span class="hljs-literal">null</span>)<br>        &#123;<br>            <span class="hljs-built_in">string</span> key = propertyValue.ToString();<br>            <span class="hljs-keyword">if</span> (!existingDataMap.ContainsKey(key))<br>            &#123;<br>                existingDataMap.Add(key, item);<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">// 替换newData中的项</span><br>    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i &lt; newData.Count; i++)<br>    &#123;<br>        <span class="hljs-keyword">var</span> itemToReplace = newData[i];<br>        <span class="hljs-keyword">var</span> propertyValue = GetPropertyValue(itemToReplace, propertyName);<br>        <span class="hljs-keyword">if</span> (propertyValue != <span class="hljs-literal">null</span>)<br>        &#123;<br>            <span class="hljs-built_in">string</span> key = propertyValue.ToString();<br>            <span class="hljs-keyword">if</span> (existingDataMap.ContainsKey(key))<br>            &#123;<br>                newData[i] = existingDataMap[key];<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">return</span> newData;<br>&#125;<br></code></pre></td></tr></table></figure><p>该方法用于将新数据与本地数据进行合并。它接收一个<code>List&lt;T&gt;</code>类型的参数<code>newData</code>，表示新数据列表，以及一个<code>string</code>类型的<code>filename</code>参数，表示本地数据的文件名。方法的实现逻辑如下：</p><ol><li>调用<code>ReadData&lt;T&gt;</code>方法读取本地数据，将结果保存在<code>existingData</code>变量中。</li><li>获取用于查找本地数据的属性名，调用<code>GetPropertyName&lt;T&gt;</code>方法获取属性名。</li><li>创建一个<code>Dictionary&lt;string, T&gt;</code>类型的字典<code>existingDataMap</code>，用于存储本地数据的映射关系。</li><li>遍历本地数据列表<code>existingData</code>，获取每个数据项的属性值，并将属性值转换为字符串类型后作为字典的键，数据项作为字典的值。</li><li>创建一个循环，遍历新数据列表<code>newData</code>中的每个数据项。</li><li>获取当前要替换的数据项<code>itemToReplace</code>的属性值，并将属性值转换为字符串类型后作为字典的键。</li><li>如果字典<code>existingDataMap</code>中包含该键，则从字典中获取对应的本地数据项，并将其替换为新数据列表<code>newData</code>中的对应项。</li><li>返回合并后的新数据列表<code>newData</code>。</li></ol><h2 id="GetPropertyName-方法"><a href="#GetPropertyName-方法" class="headerlink" title="GetPropertyName 方法"></a>GetPropertyName<T> 方法</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GetPropertyName</span>&lt;<span class="hljs-title">T</span>&gt;()</span><br>&#123;<br>    Type type = <span class="hljs-keyword">typeof</span>(T);<br><br>    <span class="hljs-keyword">if</span> (type == <span class="hljs-keyword">typeof</span>(Repertory))<br>    &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;RepertoryId&quot;</span>;<br>    &#125;<br>    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-keyword">typeof</span>(Customer))<br>    &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;CustomerId&quot;</span>;<br>    &#125;<br>    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-keyword">typeof</span>(Item))<br>    &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;ItmId&quot;</span>;<br>    &#125;<br>    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-keyword">typeof</span>(Supplier))<br>    &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;SupplierId&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(type + <span class="hljs-string">&quot;类型不匹配&quot;</span>);<br>&#125;<br></code></pre></td></tr></table></figure><p>该方法用于根据数据类型<code>T</code>获取属性名。它根据不同的数据类型返回相应的属性名字符串。如果数据类型不匹配，则抛出异常。目前支持的数据类型包括<code>Repertory</code>、<code>Customer</code>、<code>Item</code>和<code>Supplier</code>, 请根据自己需要修改数据类型。</p><h2 id="GetPropertyValue-方法"><a href="#GetPropertyValue-方法" class="headerlink" title="GetPropertyValue 方法"></a>GetPropertyValue<T> 方法</h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">object</span> <span class="hljs-title">GetPropertyValue</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">T item, <span class="hljs-built_in">string</span> propertyName</span>)</span><br>&#123;<br>    <span class="hljs-comment">// 根据属性名获取属性值</span><br>    <span class="hljs-keyword">var</span> property = <span class="hljs-keyword">typeof</span>(T).GetProperty(propertyName);<br>    <span class="hljs-keyword">if</span> (property != <span class="hljs-literal">null</span>)<br>    &#123;<br>        <span class="hljs-keyword">return</span> property.GetValue(item);<br>    &#125;<br><br>    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">&quot;获取不到&quot;</span> + propertyName + <span class="hljs-string">&quot;属性值&quot;</span>);<br>&#125;<br></code></pre></td></tr></table></figure><p>该方法用于根据属性名获取数据项中的属性值。它接收一个数据项<code>item</code>和属性名字符串<code>propertyName</code>作为参数。方法的实现逻辑如下：</p><ol><li>根据数据项的类型<code>T</code>和属性名字符串<code>propertyName</code>获取属性对象。</li><li>如果属性对象不为空，则通过<code>GetValue</code>方法获取属性值，并返回属性值。</li><li>如果属性对象为空，则抛出异常，表示无法获取属性值。</li></ol><p>以上就是<code>JsonFileManager</code>类的主要方法及其功能的说明。该类提供了数据的保存、读取和合并功能，可以方便地进行数据管理和操作。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在博客中，我将介绍一个名为&lt;code&gt;JsonFileManager&lt;/code&gt;的类，该类用于管理数据的保存和读取操作，并提供了一些数据合并的方法。下面是该类的代码及其功能的详细说明。&lt;/p&gt;
&lt;h2 id=&quot;引用和命名空间&quot;&gt;&lt;a href=&quot;#引用和命名空间&quot; cla</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="C#" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/C/"/>
    
    
    <category term="C#" scheme="http://www.loquy.cn/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>在 Java 中使用 Hutool 进行数据加密和解密</title>
    <link href="http://www.loquy.cn/posts/3c28698d.html"/>
    <id>http://www.loquy.cn/posts/3c28698d.html</id>
    <published>2023-02-22T03:05:00.000Z</published>
    <updated>2023-02-22T06:39:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>加密分为三种：1、对称加密，又称为私钥加密、共享密钥加密，使用相同的密钥；2、 非对称加密，它需要两个密钥，一个是公开密钥，另一个是私有密钥；公钥用作加密，私钥则用作解密；3、摘要加密，无论用户输入什么长度的原始数据，经过计算后输出的密文都是固定长度的，不可逆。</p><p>hutool 针对这三种加密类型分别封装，并提供常用的大部分加密算法。我在此之上使用工厂模式针对这三种算法创建了一个加密和解密的模块，方便业务调用，可以根据需求继续添加其他算法，添加对象时实现共同的接口即可，以下为用到的算法：非对称加密：RSA 、SM2；对称加密：AES、DES、DESede、SM4；摘要算法：MD5、SHA-1、SHA-256、SM3。</p><h2 id="依赖"><a href="#依赖" class="headerlink" title="依赖"></a>依赖</h2><p>在项目的 pom.xml 的 dependencies 中加入以下内容:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cn.hutool<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hutool-all<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.8.12<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure><p>国密算法中的 SM2、SM3、SM4 需要引入 Bouncy Castle 依赖</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.bouncycastle<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>bcprov-jdk15to18<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.69<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure><blockquote><p>说明 bcprov-jdk15to18 的版本请前往 Maven 中央库搜索，查找对应 JDK 的最新版本。</p></blockquote><h2 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h2><h3 id="加密接口"><a href="#加密接口" class="headerlink" title="加密接口"></a>加密接口</h3><p>接口 <code>Crypto</code> 提供加密和解密以及生成秘钥的方法。</p><h4 id="生成密钥（对）"><a href="#生成密钥（对）" class="headerlink" title="生成密钥（对）"></a>生成密钥（对）</h4><p>创建一个名为 <code>Key</code> 的类，用于表示密钥。<code>Key</code> 类有两个构造函数，一个用于对称加密密钥，另一个用于非对称加密的公钥和私钥。密钥可以使用 <code>generateKey()</code> 方法生成。</p><p>对称加密密钥的生成使用 <code>SecureUtil.generateKey()</code> 方法，传入参数 <code>AlgorithmConstant.AES</code> 表示使用 AES 算法生成密钥。生成的密钥会被封装成 <code>SecretKey</code> 对象，然后作为参数传递给 <code>Key</code> 类的第一个构造函数，最终生成一个 <code>Key</code> 对象，其中包含了生成的密钥以及它们的 base64 编码形式。</p><p>非对称加密的公钥和私钥的生成使用 <code>SecureUtil.generateKeyPair()</code> 方法，传入参数 <code>AlgorithmConstant.RSA</code> 表示使用 RSA 算法生成密钥对。生成的密钥对会被封装成 <code>KeyPair</code> 对象，然后作为参数传递给 <code>Key</code> 类的第二个构造函数，最终生成一个 <code>Key</code> 对象，其中包含了生成的公钥和私钥以及它们的 base64 编码形式。</p><p>在 <code>Key</code> 类中，使用 <code>Base64</code> 类将密钥和密钥对的 byte 数组进行 base64 编码，然后存储在对应的字符串变量中，方便后续处理和传输。</p><p>1、秘钥：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> Key <span class="hljs-title function_">generateKey</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Key</span>(SecureUtil.generateKey(AlgorithmConstant.AES));<br>&#125;<br></code></pre></td></tr></table></figure><p>2、秘钥对：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> Key <span class="hljs-title function_">generateKey</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Key</span>(SecureUtil.generateKeyPair(AlgorithmConstant.RSA));<br>&#125;<br></code></pre></td></tr></table></figure><p>3、对于 <code>SecureUtil</code> 不支持使用 SM4 算法生成的秘钥可以这样获取：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> Key <span class="hljs-title function_">generateKey</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Key</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">SymmetricCrypto</span>(AlgorithmConstant.SM4).getSecretKey());<br>&#125;<br></code></pre></td></tr></table></figure><p>4、自定义 <code>Key</code> 类：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> crypto.model;<br><br><span class="hljs-keyword">import</span> cn.hutool.core.codec.Base64;<br><br><span class="hljs-keyword">import</span> javax.crypto.SecretKey;<br><span class="hljs-keyword">import</span> java.security.KeyPair;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The type Key.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2023 /02/07 13:51</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Key</span> &#123;<br><br>    <span class="hljs-keyword">private</span> SecretKey secretKey;<br>    <br>    <span class="hljs-keyword">private</span> KeyPair keyPair;<br>    <br>    <span class="hljs-keyword">private</span> String base64SecretKey;<br>    <br>    <span class="hljs-keyword">private</span> String base64PrivateKey;<br>    <br>    <span class="hljs-keyword">private</span> String base64PublicKey;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Key</span><span class="hljs-params">(SecretKey secretKey)</span> &#123;<br>        <span class="hljs-built_in">this</span>.secretKey = secretKey;<br>        setBase64SecretKey(secretKey);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Key</span><span class="hljs-params">(KeyPair keyPair)</span> &#123;<br>        <span class="hljs-built_in">this</span>.keyPair = keyPair;<br>        setBase64PrivateKey(keyPair);<br>        setBase64PublicKey(keyPair);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> SecretKey <span class="hljs-title function_">getSecretKey</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> secretKey;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setSecretKey</span><span class="hljs-params">(SecretKey secretKey)</span> &#123;<br>        <span class="hljs-built_in">this</span>.secretKey = secretKey;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> KeyPair <span class="hljs-title function_">getKeyPair</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> keyPair;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setKeyPair</span><span class="hljs-params">(KeyPair keyPair)</span> &#123;<br>        <span class="hljs-built_in">this</span>.keyPair = keyPair;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getBase64SecretKey</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> base64SecretKey;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setBase64SecretKey</span><span class="hljs-params">(SecretKey secretKey)</span> &#123;<br>        <span class="hljs-built_in">this</span>.base64SecretKey = Base64.encodeWithoutPadding(secretKey.getEncoded());<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getBase64PrivateKey</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> base64PrivateKey;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setBase64PrivateKey</span><span class="hljs-params">(KeyPair keyPair)</span> &#123;<br>        <span class="hljs-built_in">this</span>.base64PrivateKey = Base64.encodeWithoutPadding(keyPair.getPrivate().getEncoded());<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getBase64PublicKey</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> base64PublicKey;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setBase64PublicKey</span><span class="hljs-params">(KeyPair keyPair)</span> &#123;<br>        <span class="hljs-built_in">this</span>.base64PublicKey = Base64.encodeWithoutPadding(keyPair.getPublic().getEncoded());<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h4 id="对称算法"><a href="#对称算法" class="headerlink" title="对称算法"></a>对称算法</h4><p>在 <code>SymmetricCrypto</code> 类的构造方法中，使用 <code>Base64.decode(secretKey)</code> 将 Base64 编码的密钥解码为字节数组，并作为参数传递给构造方法。然后，使用 <code>encryptHex</code> 方法对明文数据进行加密并以十六进制形式返回加密后的密文。</p><p>对于解密部分的代码，实现方法和加密部分非常相似。这里使用的是 <code>SymmetricCrypto</code> 类的 <code>decryptStr</code> 方法将十六进制的密文解密为明文，并指定解密后的编码格式为 UTF-8。</p><p>需要注意的是，代码中还有一个 <code>isBase64()</code> 方法，用于检查给定的密钥字符串是否是合法的 Base64 编码格式。如果密钥不是合法的 Base64 编码格式，会抛出异常。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">default</span> String <span class="hljs-title function_">symmetricEncrypt</span><span class="hljs-params">(String data, String secretKey, String algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    isBase64(secretKey, <span class="hljs-string">&quot;密钥&quot;</span>);<br>    <span class="hljs-type">SymmetricCrypto</span> <span class="hljs-variable">symmetricCrypto</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SymmetricCrypto</span>(algorithm, Base64.decode(secretKey));<br>    <span class="hljs-keyword">return</span> symmetricCrypto.encryptHex(data);<br>&#125;<br><br><span class="hljs-keyword">default</span> String <span class="hljs-title function_">symmetricDecrypt</span><span class="hljs-params">(String data, String secretKey, String algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    isBase64(secretKey, <span class="hljs-string">&quot;密钥&quot;</span>);<br>    <span class="hljs-type">SymmetricCrypto</span> <span class="hljs-variable">symmetricCrypto</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SymmetricCrypto</span>(algorithm, Base64.decode(secretKey));<br>    <span class="hljs-keyword">return</span> symmetricCrypto.decryptStr(data, CharsetUtil.CHARSET_UTF_8);<br>&#125;<br></code></pre></td></tr></table></figure><h4 id="非对称算法"><a href="#非对称算法" class="headerlink" title="非对称算法"></a>非对称算法</h4><p><code>AsymmetricCrypto</code> 类的构造方法中传入指定算法名称和公钥参数，并调用 <code>encryptHex()</code> 方法对待加密的数据进行加密，最终返回加密后的十六进制字符串。</p><p>在解密过程中，首先使用 <code>isBase64()</code> 函数对私钥参数进行验证，确保其为 Base64 编码格式。接着，使用 <code>AsymmetricCrypto</code> 类的构造方法中传入指定算法名称和私钥参数，并调用 <code>decryptStr()</code> 方法对待解密的数据进行解密，最终返回解密后的字符串。</p><p>需要注意的是，这里的加密和解密使用的是不同的密钥，因此需要分别使用公钥和私钥。这种非对称加密方式相对对称加密更加安全，因为不同的密钥用于加密和解密，不易被攻击者破解。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><br><span class="hljs-keyword">default</span> String <span class="hljs-title function_">asymmetricEncrypt</span><span class="hljs-params">(String data, String publicKey, String algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    isBase64(publicKey, <span class="hljs-string">&quot;公钥&quot;</span>);<br>    <span class="hljs-type">AsymmetricCrypto</span> <span class="hljs-variable">asymmetricCrypto</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsymmetricCrypto</span>(algorithm, <span class="hljs-literal">null</span>, publicKey);<br>    <span class="hljs-keyword">return</span> asymmetricCrypto.encryptHex(data, KeyType.PublicKey);<br>&#125;<br><br><span class="hljs-keyword">default</span> String <span class="hljs-title function_">asymmetricDecrypt</span><span class="hljs-params">(String data, String privateKey, String algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    isBase64(privateKey, <span class="hljs-string">&quot;私钥&quot;</span>);<br>    <span class="hljs-type">AsymmetricCrypto</span> <span class="hljs-variable">asymmetricCrypto</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsymmetricCrypto</span>(algorithm, privateKey, <span class="hljs-literal">null</span>);<br>    <span class="hljs-keyword">return</span> asymmetricCrypto.decryptStr(data, KeyType.PrivateKey);<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="摘要接口"><a href="#摘要接口" class="headerlink" title="摘要接口"></a>摘要接口</h3><p>接口 <code>Digest</code> 的 <code>digestHex(String data, String algorithm)</code> 方法接收两个参数：一个是数据，另一个是指定算法。它利用 Hutool 库中的 <code>Digester</code> 类来计算消息摘要，并返回摘要的 16 进制字符串表示。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">default</span> String <span class="hljs-title function_">digestHex</span><span class="hljs-params">(String data, String algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    <span class="hljs-type">Digester</span> <span class="hljs-variable">digester</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Digester</span>(algorithm);<br>    <span class="hljs-keyword">return</span> digester.digestHex(data);<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="工厂"><a href="#工厂" class="headerlink" title="工厂"></a>工厂</h2><p>1、使用加密工厂创建加密接口的算法：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> crypto;<br><br><span class="hljs-keyword">import</span> crypto.asymmetric.RSA;<br><span class="hljs-keyword">import</span> crypto.asymmetric.SM2;<br><span class="hljs-keyword">import</span> crypto.constant.AlgorithmConstant;<br><span class="hljs-keyword">import</span> crypto.model.Algorithm;<br><span class="hljs-keyword">import</span> crypto.symmetric.AES;<br><span class="hljs-keyword">import</span> crypto.symmetric.DES;<br><span class="hljs-keyword">import</span> crypto.symmetric.DESede;<br><span class="hljs-keyword">import</span> crypto.symmetric.SM4;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 加密算法工厂类</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2023/02/07 10:03</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CryptoFactory</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Crypto <span class="hljs-title function_">getCryptoFactory</span><span class="hljs-params">(Algorithm algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-keyword">switch</span> (algorithm.getPkAlgorithm()) &#123;<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.DES:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DES</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.DES3:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DESede</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.AES:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AES</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.SM4:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SM4</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.RSA:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RSA</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.SM2:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SM2</span>(algorithm);<br>            <span class="hljs-keyword">default</span>:<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(<span class="hljs-string">&quot;没有找到此算法：&quot;</span> + algorithm.getPkAlgorithm());<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>2、使用摘要工厂创建摘要接口的算法：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> crypto;<br><br><span class="hljs-keyword">import</span> crypto.constant.AlgorithmConstant;<br><span class="hljs-keyword">import</span> crypto.digest.MD5;<br><span class="hljs-keyword">import</span> crypto.digest.SHA1;<br><span class="hljs-keyword">import</span> crypto.digest.SHA256;<br><span class="hljs-keyword">import</span> crypto.digest.SM3;<br><span class="hljs-keyword">import</span> crypto.model.Algorithm;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2023/02/09 9:23</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DigestFactory</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Digest <span class="hljs-title function_">getDigestFactory</span><span class="hljs-params">(Algorithm algorithm)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-keyword">switch</span> (algorithm.getHashAlgorithm()) &#123;<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.MD5:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">MD5</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.SHA1:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SHA1</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.SHA256:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SHA256</span>(algorithm);<br>            <span class="hljs-keyword">case</span> AlgorithmConstant.SM3:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SM3</span>(algorithm);<br>            <span class="hljs-keyword">default</span>:<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(<span class="hljs-string">&quot;没有找到此算法：&quot;</span> + algorithm.getHashAlgorithm());<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>3、调用示例：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-type">String</span> <span class="hljs-variable">encrypt</span> <span class="hljs-operator">=</span> CryptoFactory.getCryptoFactory(algorithm).encrypt();<br><span class="hljs-type">String</span> <span class="hljs-variable">decrypt</span> <span class="hljs-operator">=</span> CryptoFactory.getCryptoFactory(algorithm).decrypt();<br><span class="hljs-type">String</span> <span class="hljs-variable">digest</span> <span class="hljs-operator">=</span> DigestFactory.getDigestFactory(algorithm).digestHex();<br></code></pre></td></tr></table></figure><h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> crypto;<br><br><span class="hljs-keyword">import</span> crypto.constant.AlgorithmConstant;<br><span class="hljs-keyword">import</span> crypto.model.Algorithm;<br><span class="hljs-keyword">import</span> crypto.model.Key;<br><span class="hljs-keyword">import</span> org.junit.jupiter.api.Test;<br><span class="hljs-keyword">import</span> org.springframework.boot.test.context.SpringBootTest;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2023/02/21 15:14</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@SpringBootTest</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CryptoTests</span> &#123;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">asymmetricTest</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        cryptoTest(AlgorithmConstant.RSA, <span class="hljs-string">&quot;RSA&quot;</span>);<br>        cryptoTest(AlgorithmConstant.SM2, <span class="hljs-string">&quot;SM2&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">symmetricTest</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        cryptoTest(AlgorithmConstant.AES, <span class="hljs-string">&quot;AES&quot;</span>);<br>        cryptoTest(AlgorithmConstant.DES, <span class="hljs-string">&quot;DES&quot;</span>);<br>        cryptoTest(AlgorithmConstant.DES3, <span class="hljs-string">&quot;DESede&quot;</span>);<br>        cryptoTest(AlgorithmConstant.SM4, <span class="hljs-string">&quot;SM4&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">digestTest</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        digestTest(AlgorithmConstant.MD5, <span class="hljs-string">&quot;MD5&quot;</span>);<br>        digestTest(AlgorithmConstant.SHA1, <span class="hljs-string">&quot;SHA1&quot;</span>);<br>        digestTest(AlgorithmConstant.SHA256, <span class="hljs-string">&quot;SHA256&quot;</span>);<br>        digestTest(AlgorithmConstant.SM3, <span class="hljs-string">&quot;SM3&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">cryptoTest</span><span class="hljs-params">(String algorithmName, String data)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">Algorithm</span> <span class="hljs-variable">algorithm</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Algorithm</span>(algorithmName, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, data);<br>        <span class="hljs-type">Key</span> <span class="hljs-variable">key</span> <span class="hljs-operator">=</span> CryptoFactory.getCryptoFactory(algorithm).generateKey();<br>        algorithm.setKey(key.getBase64SecretKey());<br>        algorithm.setPrivateKey(key.getBase64PrivateKey());<br>        algorithm.setPublicKey(key.getBase64PublicKey());<br>        <span class="hljs-type">String</span> <span class="hljs-variable">encrypt</span> <span class="hljs-operator">=</span> CryptoFactory.getCryptoFactory(algorithm).encrypt();<br>        algorithm.setRawData(encrypt);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">decrypt</span> <span class="hljs-operator">=</span> CryptoFactory.getCryptoFactory(algorithm).decrypt();<br>        System.out.println(<span class="hljs-string">&quot;=====================&quot;</span>);<br>        System.out.println(encrypt);<br>        System.out.println(decrypt);<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">digestTest</span><span class="hljs-params">(String algorithmName, String data)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">Algorithm</span> <span class="hljs-variable">algorithm</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Algorithm</span>(<span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, algorithmName, data);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">encrypt</span> <span class="hljs-operator">=</span> DigestFactory.getDigestFactory(algorithm).digestHex();<br>        System.out.println(<span class="hljs-string">&quot;=====================&quot;</span>);<br>        System.out.println(encrypt);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><p><code>asymmetricTest</code></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs text">=====================<br>075f2c0e81a54517cd61631668e9b5568e6082e69bf70e93a0996861ce365cad6385b25eaa75f77107595743dd6892e98e78b126369371068f68ff18e0d70cc86a42a74a3726b24d8bd6e53e4635c8faccb4185bdafc4d2ba9c6270db14ddff8633be84d78625775a7c8948719761245bcdc9a8e3a02b42b5e6d0a28352ca2bb<br>RSA<br>=====================<br>0403196b4d211e9af36725da6782f31ff524804057ec7e32b27ae1a79c6065fdb33d2f9a5304a6e039528d53cc7a46dac318497558c00b7865d5f859a6eca28caf0bddf74dcb337d14c58d2392be6fc92ecde35fdb3213a3dfe474ea853ad891260028c5<br>SM2<br><br></code></pre></td></tr></table></figure><p><code>digestTest</code></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs text">=====================<br>7f138a09169b250e9dcb378140907378<br>=====================<br>e1744a525099d9a53c0460ef9cb7ab0e4c4fc939<br>=====================<br>b3abe5d8c69b38733ad57ea75e83bcae42bbbbac75e3a5445862ed2f8a2cd677<br>=====================<br>17a7fa246c4b9b527fb778792b91e3ec1cc51301311801613e1a7783ebcfe2e5<br><br><br></code></pre></td></tr></table></figure><p><code>symmetricTest</code></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs text">=====================<br>6c073cdf45fa0fdf8e5bdb10d3615a0e<br>AES<br>=====================<br>e3512db314d44c2e<br>DES<br>=====================<br>54c3bf117d4c10b5<br>DESede<br>=====================<br>8b3be8b1fb505de0baa48cb5181a7974<br>SM4<br></code></pre></td></tr></table></figure><h2 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h2><p><a href="https://github.com/loquy/spring-boot-demo">参见此仓库</a></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;加密分为三种：1、对称加密，又称为私钥加密、共享密钥加密，使用相同的密钥；2、 非对称加密，它需要两个密钥，一个是公开密钥，另一个是私有密钥</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
  </entry>
  
  <entry>
    <title>在线运行 Java 代码的原理及实现</title>
    <link href="http://www.loquy.cn/posts/def20d69.html"/>
    <id>http://www.loquy.cn/posts/def20d69.html</id>
    <published>2023-02-20T09:06:00.000Z</published>
    <updated>2023-02-21T02:03:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>在线运行 Java 代码是指用户在浏览器中输入 Java 代码，通过在线编译和加载，最终在服务器上运行代码并返回结果。这种技术被广泛应用于在线编程学习、在线面试和在线评测等场景。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><h3 id="动态编译"><a href="#动态编译" class="headerlink" title="动态编译"></a>动态编译</h3><p>Java 的动态编译是指在运行时将 Java 代码编译成字节码的过程。Java 提供了一个标准的 API：<code>JavaCompiler</code> 和 <code>ToolProvider</code>，可以用来进行动态编译。在动态编译时，需要将 Java 代码转换为 <code>JavaFileObject</code> 对象，然后通过 <code>JavaCompiler.getTask()</code> 方法来编译 <code>JavaFileObject</code> 对象。在编译过程中，可以使用 <code>DiagnosticCollector</code> 类来收集编译过程中的错误和警告信息。</p><h3 id="动态加载"><a href="#动态加载" class="headerlink" title="动态加载"></a>动态加载</h3><p>Java 的动态加载是指在运行时将编译好的字节码加载到内存中，并生成对应的 class 对象的过程。Java 提供了一个标准的 API：<code>ClassLoader</code>，可以用来进行动态加载。通过自定义 <code>ClassLoader</code> 类来加载字节码，然后调用 <code>ClassLoader.loadClass()</code> 方法即可加载类。</p><h3 id="线程的限制"><a href="#线程的限制" class="headerlink" title="线程的限制"></a>线程的限制</h3><p>在线运行 Java 代码需要考虑线程的限制和安全性控制。为了避免在线运行的代码对服务器产生过多的负载，可以使用线程池来限制并发访问以及设置超时时间停止线程。</p><h3 id="安全性控制"><a href="#安全性控制" class="headerlink" title="安全性控制"></a>安全性控制</h3><p>为了保证在线运行的代码安全性，需要限制在线运行的代码只能访问一些受控的资源，并且禁止访问其他资源。Java 提供了一个安全管理器（<code>SecurityManager</code>）来控制代码的安全性，可以在代码运行前启用安全管理器，限制代码的访问权限。</p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><h3 id="编译器"><a href="#编译器" class="headerlink" title="编译器"></a>编译器</h3><p><code>ScriptCompiler</code> 类实现了一个动态编译和执行 Java 代码，主要功能包括：</p><ul><li>编译 Java 代码字符串为 Java Class，并加载该 Class。</li><li>执行该 Class 中的 Main 方法，并将输出结果返回。</li></ul><p>包括以下几个主要步骤：</p><ul><li>使用 Java Compiler API 编译 Java 代码字符串为 Java Class。<ul><li>利用 Java Compiler API 获取系统默认的 <code>JavaCompiler</code>，然后创建一个 <code>DiagnosticCollector</code> 用于收集编译过程中的诊断信息。</li><li>使用 <code>StandardJavaFileManager</code> 创建一个 <code>JavaFileObject</code> 对象，表示一个源代码文件，将 Java 代码字符串作为文件内容。</li><li>设置编译选项，这里设置了编译输出目录和编译源文件列表。</li><li>调用 <code>CompilationTask</code> 的 <code>call()</code> 方法编译 Java 代码，如果编译失败，则将诊断信息拼接成字符串并抛出异常。</li></ul></li><li>使用自定义的 <code>ClassLoader</code> 加载编译好的 Java Class。<ul><li><code>ScriptLoader</code> 首先将类名转换成类文件名，然后从指定的路径中加载对应的类文件，返回该类的 class 对象。</li></ul></li><li>执行编译好的 Java Class 的 Main 方法，并将输出结果返回。<ul><li>创建一个 <code>ByteArrayOutputStream</code> 对象用于缓存执行结果。</li><li>使用 <code>System.setOut()</code> 方法将 <code>System.out</code> 的输出重定向到缓存输出流中。</li><li>通过反射获取 Main 方法并执行，将传入的参数作为 Main 方法的参数，执行过程中会输出内容到缓存输出流中。</li><li>将缓存输出流中的内容转换成字符串并返回，同时将 <code>System.out</code> 重定向回原来的输出流。</li></ul></li><li>对执行 Main 方法进行安全控制，防止代码执行恶意操作。<ul><li>在执行 Main 方法之前和之后，调用 <code>ScriptSecurityManager</code> 的相关方法进行安全控制，限制了代码执行的权限和行为，防止代码执行恶意操作。</li></ul></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> script;<br><br><span class="hljs-keyword">import</span> javax.tools.*;<br><span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream;<br><span class="hljs-keyword">import</span> java.io.PrintStream;<br><span class="hljs-keyword">import</span> java.lang.reflect.InvocationTargetException;<br><span class="hljs-keyword">import</span> java.lang.reflect.Method;<br><span class="hljs-keyword">import</span> java.net.URI;<br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.Arrays;<br><span class="hljs-keyword">import</span> java.util.Collections;<br><span class="hljs-keyword">import</span> java.util.List;<br><span class="hljs-keyword">import</span> java.util.concurrent.*;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ScriptCompiler</span> &#123;<br><br>    <span class="hljs-keyword">public</span> Class&lt;?&gt; compile(String javaSource) <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">JavaCompiler</span> <span class="hljs-variable">javaCompiler</span> <span class="hljs-operator">=</span> ToolProvider.getSystemJavaCompiler();<br>        DiagnosticCollector&lt;JavaFileObject&gt; diagnosticsCollector = <span class="hljs-keyword">new</span> <span class="hljs-title class_">DiagnosticCollector</span>&lt;&gt;();<br>        <span class="hljs-type">StandardJavaFileManager</span> <span class="hljs-variable">standardFileManager</span> <span class="hljs-operator">=</span> javaCompiler.getStandardFileManager(<span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>);<br>        <span class="hljs-type">JavaFileObject</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringObject</span>(ScriptConstant.CLASS_NAME, javaSource);<br>        Iterable&lt;String&gt; options = Arrays.asList(<span class="hljs-string">&quot;-d&quot;</span>, ScriptConstant.CLASS_PATH);<br>        Iterable&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">JavaFileObject</span>&gt; files = Collections.singletonList(file);<br><br>        JavaCompiler.<span class="hljs-type">CompilationTask</span> <span class="hljs-variable">task</span> <span class="hljs-operator">=</span> javaCompiler.getTask(<span class="hljs-literal">null</span>, standardFileManager, diagnosticsCollector, options, <span class="hljs-literal">null</span>, files);<br>        <span class="hljs-type">Boolean</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> task.call();<br>        <span class="hljs-keyword">if</span> (!result) &#123;<br>            <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">diagnosticString</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();<br>            List&lt;Diagnostic&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">JavaFileObject</span>&gt;&gt; diagnostics = diagnosticsCollector.getDiagnostics();<br>            <span class="hljs-keyword">for</span> (Diagnostic&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">JavaFileObject</span>&gt; diagnostic : diagnostics) &#123;<br>                diagnosticString.append(diagnostic);<br>            &#125;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(<span class="hljs-string">&quot;编译失败，请检查语法是否正确，具体错误：&quot;</span> + diagnosticString);<br>        &#125;<br>        <span class="hljs-keyword">return</span> loadClass(<span class="hljs-string">&quot;Main&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 加载CLASS</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> className 类名</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> class文件</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Class&lt;?&gt; loadClass(String className) <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">//用自定义classLoader加载这个class</span><br>        <span class="hljs-type">ScriptLoader</span> <span class="hljs-variable">scriptLoader</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptLoader</span>(getClass().getClassLoader());<br>        <span class="hljs-keyword">return</span> scriptLoader.loadClass(className);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">executeMainMethod</span><span class="hljs-params">(Class&lt;?&gt; clazz, Long timeLimit, String[] args)</span> <span class="hljs-keyword">throws</span> ScriptException &#123;<br>        <span class="hljs-keyword">final</span> <span class="hljs-type">ExecutorService</span> <span class="hljs-variable">executorService</span> <span class="hljs-operator">=</span> Executors.newFixedThreadPool(<span class="hljs-number">10</span>);<br>        List&lt;FutureTask&lt;String&gt;&gt; futureTaskList = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        Callable&lt;String&gt; mainMethodExecuteCallable = () -&gt; executeMainMethodWithClass(clazz, args);<br>        FutureTask&lt;String&gt; futureTask = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FutureTask</span>&lt;&gt;(mainMethodExecuteCallable);<br>        futureTaskList.add(futureTask);<br>        executorService.submit(futureTask);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;<br>        FutureTask&lt;String&gt; taskItem = futureTaskList.get(<span class="hljs-number">0</span>);<br>        <span class="hljs-keyword">try</span> &#123;<br>            result = taskItem.get(timeLimit, TimeUnit.MILLISECONDS);<br>        &#125; <span class="hljs-keyword">catch</span> (TimeoutException e) &#123;<br>            taskItem.cancel(<span class="hljs-literal">true</span>);<br>            e.printStackTrace();<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptException</span>(<span class="hljs-string">&quot;运行超时了！限定时间为:&quot;</span> + timeLimit + <span class="hljs-string">&quot;毫秒&quot;</span>);<br>        &#125; <span class="hljs-keyword">catch</span> (SecurityException | ExecutionException | InterruptedException e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptException</span>(<span class="hljs-string">&quot;执行失败，请检查代码是否含有危险操作，具体错误：&quot;</span> + e.getMessage());<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br><br><br>    <span class="hljs-keyword">private</span> String <span class="hljs-title function_">executeMainMethodWithClass</span><span class="hljs-params">(Class&lt;?&gt; clazz, String[] args)</span> <span class="hljs-keyword">throws</span> ScriptException &#123;<br>        <span class="hljs-type">ByteArrayOutputStream</span> <span class="hljs-variable">baoStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ByteArrayOutputStream</span>(<span class="hljs-number">1024</span>);<br>        <span class="hljs-type">PrintStream</span> <span class="hljs-variable">cacheStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">PrintStream</span>(baoStream);<br>        <span class="hljs-type">PrintStream</span> <span class="hljs-variable">oldStream</span> <span class="hljs-operator">=</span> System.out;<br>        System.setOut(cacheStream);<br>        <span class="hljs-comment">//执行Main方法</span><br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">long</span> <span class="hljs-variable">threadId</span> <span class="hljs-operator">=</span> Thread.currentThread().getId();<br>            ScriptSecurityManager.initPermission(threadId);<br>            <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getMethod(<span class="hljs-string">&quot;main&quot;</span>, String[].class);<br>            method.invoke(<span class="hljs-literal">null</span>, (Object) args);<br>            ScriptSecurityManager.destroyPermission();<br>        &#125; <span class="hljs-keyword">catch</span> (InvocationTargetException e) &#123;<br>            <span class="hljs-comment">// 获取目标异常</span><br>            <span class="hljs-type">Throwable</span> <span class="hljs-variable">t</span> <span class="hljs-operator">=</span> e.getTargetException();<br>            t.printStackTrace();<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptException</span>(t.getMessage());<br>        &#125; <span class="hljs-keyword">catch</span> (IllegalAccessException | NoSuchMethodException e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptException</span>(e.getMessage());<br>        &#125; <span class="hljs-keyword">finally</span> &#123;<br>            ScriptSecurityManager.destroyPermission();<br>        &#125;<br>        System.setOut(oldStream);<br>        <span class="hljs-keyword">return</span> baoStream.toString();<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">StringObject</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">SimpleJavaFileObject</span> &#123;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String contents;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-title function_">StringObject</span><span class="hljs-params">(String className, String contents)</span> &#123;<br>            <span class="hljs-built_in">super</span>(URI.create(<span class="hljs-string">&quot;String:///&quot;</span> + className + Kind.SOURCE.extension), Kind.SOURCE);<br>            <span class="hljs-built_in">this</span>.contents = contents;<br>        &#125;<br><br>        <span class="hljs-meta">@Override</span><br>        <span class="hljs-keyword">public</span> CharSequence <span class="hljs-title function_">getCharContent</span><span class="hljs-params">(<span class="hljs-type">boolean</span> ignoreEncodingErrors)</span> &#123;<br>            <span class="hljs-keyword">return</span> contents;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">code</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;    import java.io.*;\n&quot;</span> +<br>                <span class="hljs-string">&quot;    public class Main &#123;\n&quot;</span> +<br>                <span class="hljs-string">&quot;        public static void main(String[] args) throws InterruptedException&#123;\n&quot;</span> +<br>                <span class="hljs-string">&quot;            File file = new File(\&quot;D:\\\\test\&quot;);\n&quot;</span> +<br>                <span class="hljs-string">&quot;            System.out.println(args[0]);\n&quot;</span> +<br><span class="hljs-comment">//                &quot;            boolean delete = file.delete();\n&quot; +</span><br><span class="hljs-comment">//                &quot; for (int i = 10; i&gt;=0; i--) &#123;\n&quot; +</span><br><span class="hljs-comment">//                &quot; Thread.sleep(1000);  \n&quot; +</span><br><span class="hljs-comment">//                &quot; &#125;\n&quot; +</span><br><span class="hljs-comment">//                &quot;            System.out.println(delete);\n&quot; +</span><br><span class="hljs-comment">//                &quot;            System.exit(0);\n&quot; +</span><br>                <span class="hljs-string">&quot;        &#125;\n&quot;</span> +<br>                <span class="hljs-string">&quot;    &#125;&quot;</span>;<br>        System.out.println(code);<br>        <span class="hljs-type">ScriptCompiler</span> <span class="hljs-variable">scriptCompiler</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptCompiler</span>();<br>        <span class="hljs-keyword">try</span> &#123;<br>            Class&lt;?&gt; clazz = scriptCompiler.compile(code);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">string</span> <span class="hljs-operator">=</span> scriptCompiler.executeMainMethod(clazz, <span class="hljs-number">1000L</span>, <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>[]&#123;<span class="hljs-string">&quot;123&quot;</span>&#125;);<br>            System.out.println(<span class="hljs-string">&quot;---------&gt;&quot;</span> + string);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            System.out.println(e.getMessage());<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></details><h3 id="常量"><a href="#常量" class="headerlink" title="常量"></a>常量</h3><p><code>ScriptConstant</code> 类的作用是为编译脚本文件提供一个固定的目录，该目录下的脚本文件会被编译为 Java 类并在运行时执行。</p><ul><li><code>CLASS_NAME</code> 常量为字符串 “Main”。</li><li><code>CLASS_PATH</code> 常量为调用了 <code>createScriptDir()</code> 方法的返回值。</li><li><code>createScriptDir()</code> 是一个静态方法，它的作用是创建一个名为 “custom-script” 的目录，并返回该目录的路径作为 CLASS_PATH 常量的值。具体实现如下：<ul><li>通过 <code>ScriptConstant.class.getProtectionDomain().getCodeSource().getLocation().getPath()</code> 方法获取当前类的绝对路径。</li><li>将路径字符串按照 UTF-8 编码方式进行解码，以避免因为路径中存在特殊字符导致的问题。</li><li>获取当前路径的父目录和其父目录的路径，即 <code>resource</code> 目录。</li><li>将 <code>resource + File.separator + &quot;custom-script&quot; + File.separator</code> 赋值给 <code>customScriptPath</code> 变量，表示要创建的目录名。</li><li>创建 <code>customScript</code> 目录，并将 <code>customScriptPath</code> 作为 CLASS_PATH 常量的值返回。</li></ul></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> script;<br><br><span class="hljs-keyword">import</span> java.io.File;<br><span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ScriptConstant</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">CLASS_NAME</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Main&quot;</span>;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">CLASS_PATH</span> <span class="hljs-operator">=</span> createScriptDir();<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">createScriptDir</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> ScriptConstant.class.getProtectionDomain().getCodeSource().getLocation().getPath();<br>        <span class="hljs-keyword">try</span> &#123;<br>            path = java.net.URLDecoder.decode(path, <span class="hljs-string">&quot;UTF-8&quot;</span>);<br>        &#125; <span class="hljs-keyword">catch</span> (UnsupportedEncodingException e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>        <span class="hljs-type">File</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path);<br>        <span class="hljs-type">File</span> <span class="hljs-variable">parent</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(file.getParent());<br>        <span class="hljs-type">File</span> <span class="hljs-variable">resource</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(parent.getParent());<br>        <span class="hljs-type">String</span> <span class="hljs-variable">customScriptPath</span> <span class="hljs-operator">=</span> resource + File.separator + <span class="hljs-string">&quot;custom-script&quot;</span> + File.separator;<br>        <span class="hljs-type">File</span> <span class="hljs-variable">customScript</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(customScriptPath);<br>        <span class="hljs-keyword">if</span> (!customScript.exists()) &#123;<br>            customScript.mkdirs();<br>        &#125;<br>        <span class="hljs-keyword">return</span> customScriptPath;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></details><h3 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h3><p><code>ScriptException</code> 的异常类继承自 <code>SecurityException</code> 类。该类通过 <code>public ScriptException(String message)</code> 构造函数提供了一个带有字符串参数的构造函数，用于创建一个新的 <code>ScriptException</code> 对象，这个对象包含了给定的字符串消息。</p><p>这个自定义的异常类可能用于在处理脚本时发生错误时抛出异常。例如，当脚本执行时发生安全性异常时，就可以抛出这个自定义的异常，以便在调用脚本的代码中处理异常并采取适当的措施。</p><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> script;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ScriptException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">SecurityException</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">ScriptException</span><span class="hljs-params">(String message)</span> &#123;<br>        <span class="hljs-built_in">super</span>(message);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></details><h3 id="类加载器"><a href="#类加载器" class="headerlink" title="类加载器"></a>类加载器</h3><p>继承自 <code>ClassLoader</code> 的 <code>ScriptLoader</code> 类，用于在运行时动态加载自定义脚本。</p><p>该类重写了 <code>findClass()</code> 方法，在此方法中，将类名转换为类文件的路径，然后通过 <code>getClassFileBytes()</code> 方法读取该路径下的 class 文件，并返回其字节码。最后，使用 <code>defineClass()</code> 方法将字节码转化为 Java 类的实例，并返回该类的 class 对象。</p><p><code>getClassFileBytes()</code> 方法使用了 NIO 的方式读取 class 文件。该方法通过 <code>FileInputStream</code> 打开 class 文件，然后通过 <code>FileChannel</code> 读取文件数据，并使用 <code>ByteBuffer</code> 缓存数据，最后通过 <code>WritableByteChannel</code> 将数据写入到 <code>ByteArrayOutputStream</code> 中，并返回其字节数组。</p><p>该脚本加载器通过在 <code>findClass()</code> 方法中动态加载 class 文件，使得程序可以在运行时动态的调用一些自定义的 Java 脚本。</p><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> script;<br><br><span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream;<br><span class="hljs-keyword">import</span> java.io.FileInputStream;<br><span class="hljs-keyword">import</span> java.nio.ByteBuffer;<br><span class="hljs-keyword">import</span> java.nio.channels.Channels;<br><span class="hljs-keyword">import</span> java.nio.channels.FileChannel;<br><span class="hljs-keyword">import</span> java.nio.channels.WritableByteChannel;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ScriptLoader</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">ClassLoader</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">ScriptLoader</span><span class="hljs-params">(ClassLoader parent)</span> &#123;<br>        <span class="hljs-built_in">super</span>(parent);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> Class&lt;?&gt; findClass(String name) &#123;<br>        <span class="hljs-comment">//将包转为目录</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">classPath</span> <span class="hljs-operator">=</span> name.replace(<span class="hljs-string">&quot;.&quot;</span>, <span class="hljs-string">&quot;\\&quot;</span>) + <span class="hljs-string">&quot;.class&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">classFile</span> <span class="hljs-operator">=</span> ScriptConstant.CLASS_PATH + classPath;<br>        Class&lt;?&gt; clazz = <span class="hljs-literal">null</span>;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">byte</span>[] data = getClassFileBytes(classFile);<br>            clazz = defineClass(name, data, <span class="hljs-number">0</span>, data.length);<br>            <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> == clazz) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(<span class="hljs-string">&quot;类加载器里不能找到这个类&quot;</span>);<br>            &#125;<br><br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>        <span class="hljs-keyword">return</span> clazz;<br><br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">byte</span>[] getClassFileBytes(String classFile) <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">//采用NIO读取</span><br>        <span class="hljs-type">FileInputStream</span> <span class="hljs-variable">fis</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(classFile);<br>        <span class="hljs-type">FileChannel</span> <span class="hljs-variable">fileC</span> <span class="hljs-operator">=</span> fis.getChannel();<br>        <span class="hljs-type">ByteArrayOutputStream</span> <span class="hljs-variable">baos</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ByteArrayOutputStream</span>();<br>        <span class="hljs-type">WritableByteChannel</span> <span class="hljs-variable">outC</span> <span class="hljs-operator">=</span> Channels.newChannel(baos);<br>        <span class="hljs-type">ByteBuffer</span> <span class="hljs-variable">buffer</span> <span class="hljs-operator">=</span> ByteBuffer.allocateDirect(<span class="hljs-number">1024</span>);<br>        <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) &#123;<br>            <span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> fileC.read(buffer);<br>            <span class="hljs-keyword">if</span> (i == <span class="hljs-number">0</span> || i == -<span class="hljs-number">1</span>) &#123;<br>                <span class="hljs-keyword">break</span>;<br>            &#125;<br>            buffer.flip();<br>            outC.write(buffer);<br>            buffer.clear();<br>        &#125;<br>        fis.close();<br>        <span class="hljs-keyword">return</span> baos.toByteArray();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></details><h3 id="安全管理器"><a href="#安全管理器" class="headerlink" title="安全管理器"></a>安全管理器</h3><p>继承自 <code>SecurityManager</code> 的 <code>ScriptSecurityManager</code> 类是一个用于控制 Java 应用程序的安全权限的自定义安全管理器，通过 <code>initPermission()</code> 和 <code>destroyPermission()</code> 方法设置安全管理器，并通过 <code>check()</code> 方法检查和控制权限请求。</p><p><code>initPermission()</code> 方法用于设置应用程序的安全管理器，如果还没有设置，则会创建一个 <code>ScriptSecurityManager</code> 实例并将其设置为应用程序的安全管理器。它需要一个线程 ID 参数作为标识，以便在 <code>check()</code> 方法中检查权限时确定当前线程是否具有特定权限。</p><p><code>destroyPermission()</code> 方法用于撤销应用程序的安全管理器，它将之前设置的安全管理器设置为 null，并且将 <code>destroy</code> 标志设置为 true。</p><p><code>ScriptSecurityManager</code> 类重写了 <code>checkPermission()</code> 方法并在里面调用 <code>check()</code> 方法 ，在 <code>check()</code> 方法中，根据权限的类型和名称，执行不同的检查。</p><p>如果请求的权限不被允许，它将抛出一个 <code>SecurityException</code> 异常，以防止应用程序的不安全行为。</p><p>如果权限是 <code>RuntimePermission</code>，它会检查请求的名称是否包含 <code>setSecurityManager</code> 并且 <code>destroy</code> 标志为 false，如果是，则不允许设置新的安全管理器。</p><p>对于其他权限类型，它会检查请求的名称或操作是否包含特定权限的名称，并且如果包含，则不允许该请求。如果请求的权限被允许，则不会发生任何操作。</p><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> script;<br><br><span class="hljs-keyword">import</span> java.security.Permission;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ScriptSecurityManager</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">SecurityManager</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-type">boolean</span> <span class="hljs-variable">destroy</span> <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-type">long</span> threadId;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">initPermission</span><span class="hljs-params">(<span class="hljs-type">long</span> threadId)</span> &#123;<br>        <span class="hljs-type">SecurityManager</span> <span class="hljs-variable">originalSecurityManager</span> <span class="hljs-operator">=</span> System.getSecurityManager();<br>        <span class="hljs-keyword">if</span> (originalSecurityManager == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-type">SecurityManager</span> <span class="hljs-variable">sm</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptSecurityManager</span>();<br>            System.setSecurityManager(sm);<br>        &#125;<br>        ScriptSecurityManager.threadId = threadId;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">destroyPermission</span><span class="hljs-params">()</span> &#123;<br>        ScriptSecurityManager.destroy = <span class="hljs-literal">true</span>;<br>        System.setSecurityManager(<span class="hljs-literal">null</span>);<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">check</span><span class="hljs-params">(Permission perm)</span> <span class="hljs-keyword">throws</span> ScriptException &#123;<br>        <span class="hljs-type">long</span> <span class="hljs-variable">threadId</span> <span class="hljs-operator">=</span> Thread.currentThread().getId();<br>        <span class="hljs-keyword">if</span> (threadId == ScriptSecurityManager.threadId) &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">name</span> <span class="hljs-operator">=</span> perm.getName();<br>            <span class="hljs-type">String</span> <span class="hljs-variable">actions</span> <span class="hljs-operator">=</span> perm.getActions();<br>            <span class="hljs-keyword">if</span> (perm <span class="hljs-keyword">instanceof</span> RuntimePermission) &#123;<br>                <span class="hljs-type">String</span> <span class="hljs-variable">setSecurityManager</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;setSecurityManager&quot;</span>;<br>                <span class="hljs-keyword">if</span> (name.contains(setSecurityManager) &amp;&amp; !destroy) &#123;<br>                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SecurityException</span>(<span class="hljs-string">&quot;不允许设置安全管理器！&quot;</span>);<br>                &#125;<br>                checkPerm(name, <span class="hljs-string">&quot;exitVM&quot;</span>, <span class="hljs-string">&quot;不允许调用exit方法！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;loadLibrary&quot;</span>, <span class="hljs-string">&quot;不允许链接库！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;createClassLoader&quot;</span>, <span class="hljs-string">&quot;不允许创建类加载器！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;getClassLoader&quot;</span>, <span class="hljs-string">&quot;不允许获取类加载器！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;writeFileDescriptor&quot;</span>, <span class="hljs-string">&quot;不允许写入文件描述符！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;queuePrintJob&quot;</span>, <span class="hljs-string">&quot;不允许调用线程发起打印作业请求！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;setContextClassLoader&quot;</span>, <span class="hljs-string">&quot;不允许线程使用的上下文类装入器的设置！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;enableContextClassLoaderOverride&quot;</span>, <span class="hljs-string">&quot;不允许线程上下文类装入器方法的子类实现！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;closeClassLoader&quot;</span>, <span class="hljs-string">&quot;不允许关闭类加载器！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;createSecurityManager&quot;</span>, <span class="hljs-string">&quot;不允许创建一个新的安全管理器！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;shutdownHooks&quot;</span>, <span class="hljs-string">&quot;不允许注册和取消虚拟机关机钩子！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;setFactory&quot;</span>, <span class="hljs-string">&quot;不允许设置ServerSocket或socket使用的套接字工厂，或URL使用的流处理程序工厂！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;setIO&quot;</span>, <span class="hljs-string">&quot;不允许System.out、 System.in 和 System.err 的设置！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;modifyThread&quot;</span>, <span class="hljs-string">&quot;不允许线程的修改！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;defineClassInPackage&quot;</span>, <span class="hljs-string">&quot;不允许在参数指定的包中定义类！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;modifyThread&quot;</span>, <span class="hljs-string">&quot;不允许线程的修改！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;stopThread&quot;</span>, <span class="hljs-string">&quot;不允许通过调用Thread stop方法停止线程！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;modifyThreadGroup&quot;</span>, <span class="hljs-string">&quot;不允许修改线程组！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;getProtectionDomain&quot;</span>, <span class="hljs-string">&quot;不允许获取特定代码源的策略信息！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;getFileSystemAttributes&quot;</span>, <span class="hljs-string">&quot;不允许文件系统属性的检索！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;loadLibrary&quot;</span>, <span class="hljs-string">&quot;不允许指定库的动态链接！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;accessClassInPackage&quot;</span>, <span class="hljs-string">&quot;不允许通过类装入器的loadClass方法访问指定的包！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;defineClassInPackage&quot;</span>, <span class="hljs-string">&quot;不允许通过类装入器的defineClass方法定义指定包中的类！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;accessDeclaredMembers&quot;</span>, <span class="hljs-string">&quot;不允许对类的已声明成员的访问！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;queuePrintJob&quot;</span>, <span class="hljs-string">&quot;不允许打印作业请求的启动！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;getStackTrace&quot;</span>, <span class="hljs-string">&quot;不允许获取另一个线程的堆栈跟踪信息！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;setDefaultUncaughtExceptionHandler&quot;</span>, <span class="hljs-string">&quot;不允许设置当线程因未捕获异常而突然终止时使用的默认处理程序！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;preferences&quot;</span>, <span class="hljs-string">&quot;不允许允许在Preferences持久备份存储中检索或更新操作！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;usePolicy&quot;</span>, <span class="hljs-string">&quot;不允许授予禁用Java插件的默认安全提示行为！&quot;</span>);<br>            &#125;<br>            <span class="hljs-keyword">if</span> (perm <span class="hljs-keyword">instanceof</span> java.io.FilePermission) &#123;<br>                checkPerm(actions, <span class="hljs-string">&quot;execute&quot;</span>, <span class="hljs-string">&quot;不允许调用exec方法！&quot;</span>);<br>                checkPerm(actions, <span class="hljs-string">&quot;write&quot;</span>, <span class="hljs-string">&quot;不允许写入文件！&quot;</span>);<br>                checkPerm(actions, <span class="hljs-string">&quot;delete&quot;</span>, <span class="hljs-string">&quot;不允许删除文件！&quot;</span>);<br>            &#125;<br>            <span class="hljs-keyword">if</span> (perm <span class="hljs-keyword">instanceof</span> java.net.SocketPermission) &#123;<br>                checkPerm(name, <span class="hljs-string">&quot;resolve,connect&quot;</span>, <span class="hljs-string">&quot;不允许打开到指定主机和端口号的套接字连接！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;listen&quot;</span>, <span class="hljs-string">&quot;不允许在指定的本地端口号上等待连接请求！&quot;</span>);<br>                checkPerm(name, <span class="hljs-string">&quot;connect,accept&quot;</span>, <span class="hljs-string">&quot;不允许接受来自指定主机和端口号的套接字连接！&quot;</span>);<br>            &#125;<br>            <span class="hljs-keyword">if</span> (perm <span class="hljs-keyword">instanceof</span> java.util.PropertyPermission) &#123;<br>                checkPerm(name, <span class="hljs-string">&quot;read,write&quot;</span>, <span class="hljs-string">&quot;不允许访问或修改系统属性！&quot;</span>);<br>            &#125;<br>            <span class="hljs-keyword">if</span> (perm <span class="hljs-keyword">instanceof</span> java.security.SecurityPermission) &#123;<br>                checkPerm(name,<span class="hljs-string">&quot;createAccessControlContext,getDomainCombiner,getPolicy,setPolicy,createPolicy,getProperty,&quot;</span> +<br>                                <span class="hljs-string">&quot;setProperty,insertProvider,removeProvider,clearProviderProperties,putProviderProperty,removeProviderProperty&quot;</span>,<br>                        <span class="hljs-string">&quot;不允许具有指定权限目标名称的权限！&quot;</span>);<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">checkPermission</span><span class="hljs-params">(Permission perm)</span> <span class="hljs-keyword">throws</span> ScriptException &#123;<br>        check(perm);<br><br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">checkPermission</span><span class="hljs-params">(Permission perm, Object context)</span> <span class="hljs-keyword">throws</span> ScriptException &#123;<br>        check(perm);<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">checkPerm</span><span class="hljs-params">(String perm, String checks, String msg)</span> <span class="hljs-keyword">throws</span> ScriptException &#123;<br>        String[] check = checks.split(<span class="hljs-string">&quot;,&quot;</span>);<br>        <span class="hljs-keyword">for</span> (String checkPerm : check) &#123;<br>            <span class="hljs-keyword">if</span> (perm.contains(checkPerm)) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ScriptException</span>(msg);<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></details><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p><a href="https://github.com/loquy/spring-boot-demo">参见此仓库</a></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;在线运行 Java 代码是指用户在浏览器中输入 Java 代码，通过在线编译和加载，最终在服务器上运行代码并返回结果。这种技术被广泛应用于在</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
  </entry>
  
  <entry>
    <title>Java 代码生成器</title>
    <link href="http://www.loquy.cn/posts/b97e84d6.html"/>
    <id>http://www.loquy.cn/posts/b97e84d6.html</id>
    <published>2022-12-07T08:51:00.000Z</published>
    <updated>2022-12-12T00:41:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><pre><code class="hljs">代码生成器的主要目的是提高开发效率，减少重复劳动，并确保生成的代码符合一定的规范。可以使用它来自动生成那些具有一定规律性的代码，包括但不限于数据库访问层、业务逻辑层和用户界面层。它可以根据给定的数据库和表信息，使用模板生成代码，这个过程包括以下步骤：1、确定需要生成的代码。2、编写代码生成器的逻辑。3、使用模板引擎来帮助你生成代码。4、编写工具来调用你的代码生成器，并将生成的代码写入文件。</code></pre><h1 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h1><p>参考：自定义代码生成器。<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[自定义代码生成器](https://yun.itheima.com/jishu/419.html?bilibi)">[1]</span></a></sup></p><p><img src="/images/codeGenIdea.png"></p><ul><li><p>使用 Java 中的 JDBC API 来连接到数据库，并使用 SQL 查询或 <code>DatabaseMetaData</code> 接口来获取数据库表的元数据，例如表名、列名和数据类型。</p></li><li><p>使用模板引擎（如 <a href="http://freemarker.foofun.cn/">Freemarker</a> 或 <a href="https://velocity.apache.org/">Velocity</a>）来定义代码生成模板。模板可能包括普通文本和特殊标记，用于在生成代码时插入元数据。</p></li><li><p>使用 Java 代码从模板引擎加载模板，并将元数据插入模板中。最后，将生成的代码写入文件或输出到控制台。</p></li></ul><h1 id="模板引擎"><a href="#模板引擎" class="headerlink" title="模板引擎"></a>模板引擎</h1><p>参考：FreeMarker 快速入门。<sup id="fnref:2" class="footnote-ref"><a href="#fn:2" rel="footnote"><span class="hint--top hint--rounded" aria-label="[FreeMarker 快速入门](https://segmentfault.com/a/1190000011768799)">[2]</span></a></sup></p><pre><code class="hljs">FreeMarker 是一款用 java 语言编写的模版引擎，它通过提供一组指令来处理模板文件，并将数据和模板文件合并成最终的文件。FreeMarker 模板文件可以包含特殊的指令，这些指令可以控制模板的渲染方式，例如条件判断、循环语句等。程序员可以通过在模板文件中插入这些指令来定制模板的渲染方式。</code></pre><ul><li><p>特点：</p><ul><li><p>轻量级模版引擎，不需要 Servlet 环境就可以很轻松的嵌入到应用程序中。</p></li><li><p>能生成各种文本，如 html，xml，java 等。</p></li><li><p>入门简单，它是用 java 编写的，很多语法和 java 相似。</p></li></ul></li><li><p>工作原理：<br><img src="/images/FreeMarker.jpg"></p></li><li><p>使用步骤：</p><ul><li><p>加载 FreeMarker 模板引擎的类库。</p></li><li><p>设置模板文件的路径和存储数据的 Map 对象。</p></li><li><p>创建 FreeMarker 模板引擎的 <code>Configuration</code> 对象。</p></li><li><p>创建模板文件的模板对象。</p></li><li><p>程序可以通过调用 FreeMarker 的 <code>process</code> 方法，将模板文件和数据进行合并，并将合并后的结果通过 IO 流输出到指定的文件。</p></li></ul></li></ul><h1 id="数据库元数据"><a href="#数据库元数据" class="headerlink" title="数据库元数据"></a>数据库元数据</h1><p>参考：使用 JDBC 提取数据库元数据。<sup id="fnref:3" class="footnote-ref"><a href="#fn:3" rel="footnote"><span class="hint--top hint--rounded" aria-label="[使用 JDBC 提取数据库元数据](https://blog.csdn.net/niugang0920/article/details/119530050)">[3]</span></a></sup></p><p>Java 数据库元数据（<code>DatabaseMetaData</code>）是一个接口，它提供了有关数据库的元数据（即数据库的数据字典）的信息。</p><p>它可以用来获取表详细信息、获取列详细信息、获取主键详细信息等。</p><p>要使用数据库元数据，需要先使用 JDBC（Java Database Connectivity，Java 数据库连接）连接数据库，然后通过 <code>Connection</code> 对象的 <code>getMetaData</code> 方法获取 <code>DatabaseMetaData</code> 对象。</p><ul><li><p>获取表信息： <code>getTables(...)</code>。</p></li><li><p>获取列信息： <code>getColumns(...)</code>。</p></li><li><p>获取主键信息： <code>getPrimaryKeys(...)</code>。</p></li></ul><p>下面是一个简单的示例，展示了如何使用数据库元数据获取表详细信息、获取列详细信息、获取主键详细信息：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.sql.Connection;<br><span class="hljs-keyword">import</span> java.sql.DatabaseMetaData;<br><span class="hljs-keyword">import</span> java.sql.ResultSet;<br><span class="hljs-keyword">import</span> java.sql.SQLException;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MetaDataExample</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> SQLException &#123;<br>        <span class="hljs-comment">// 连接 URL</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">url</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;jdbc:mysql://localhost:3306/mydatabase&quot;</span>;<br>        <span class="hljs-comment">// 数据库用户名</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;user&quot;</span>;<br>        <span class="hljs-comment">// 数据库密码</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">password</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;password&quot;</span>;<br><br>        <span class="hljs-comment">// 建立与数据库的连接</span><br>        <span class="hljs-type">Connection</span> <span class="hljs-variable">conn</span> <span class="hljs-operator">=</span> DriverManager.getConnection(url, username, password);<br><br>        <span class="hljs-comment">// 获取数据库元数据</span><br>        <span class="hljs-type">DatabaseMetaData</span> <span class="hljs-variable">dbMetaData</span> <span class="hljs-operator">=</span> conn.getMetaData();<br><br>        <span class="hljs-comment">// 获取表的详细信息</span><br>        <span class="hljs-type">ResultSet</span> <span class="hljs-variable">tables</span> <span class="hljs-operator">=</span> dbMetaData.getTables(<span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>[] &#123;<span class="hljs-string">&quot;TABLE&quot;</span>&#125;);<br>        <span class="hljs-keyword">while</span> (tables.next()) &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">tableName</span> <span class="hljs-operator">=</span> tables.getString(<span class="hljs-string">&quot;TABLE_NAME&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">tableType</span> <span class="hljs-operator">=</span> tables.getString(<span class="hljs-string">&quot;TABLE_TYPE&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">tableRemarks</span> <span class="hljs-operator">=</span> tables.getString(<span class="hljs-string">&quot;REMARKS&quot;</span>);<br>            <span class="hljs-comment">// 输出表信息</span><br>            System.out.println(<span class="hljs-string">&quot;Table Name: &quot;</span> + tableName);<br>            System.out.println(<span class="hljs-string">&quot;Table Type: &quot;</span> + tableType);<br>            System.out.println(<span class="hljs-string">&quot;Table Remarks: &quot;</span> + tableRemarks);<br>        &#125;<br><br>        <span class="hljs-comment">// 获取列的详细信息</span><br>        <span class="hljs-type">ResultSet</span> <span class="hljs-variable">columns</span> <span class="hljs-operator">=</span> dbMetaData.getColumns(<span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">&quot;my_table&quot;</span>, <span class="hljs-literal">null</span>);<br>        <span class="hljs-keyword">while</span> (columns.next()) &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">columnName</span> <span class="hljs-operator">=</span> columns.getString(<span class="hljs-string">&quot;COLUMN_NAME&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">columnType</span> <span class="hljs-operator">=</span> columns.getString(<span class="hljs-string">&quot;TYPE_NAME&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">columnSize</span> <span class="hljs-operator">=</span> columns.getString(<span class="hljs-string">&quot;COLUMN_SIZE&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">columnRemarks</span> <span class="hljs-operator">=</span> columns.getString(<span class="hljs-string">&quot;REMARKS&quot;</span>);<br>            <span class="hljs-comment">// 输出列信息</span><br>            System.out.println(<span class="hljs-string">&quot;Column Name: &quot;</span> + columnName);<br>            System.out.println(<span class="hljs-string">&quot;Column Type: &quot;</span> + columnType);<br>            System.out.println(<span class="hljs-string">&quot;Column Size: &quot;</span> + columnSize);<br>            System.out.println(<span class="hljs-string">&quot;Column Remarks: &quot;</span> + columnRemarks);<br>        &#125;<br><br>        <span class="hljs-comment">// 获取主键的详细信息</span><br>        <span class="hljs-type">ResultSet</span> <span class="hljs-variable">primaryKeys</span> <span class="hljs-operator">=</span> dbMetaData.getPrimaryKeys(<span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">&quot;my_table&quot;</span>);<br>        <span class="hljs-keyword">while</span> (primaryKeys.next()) &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">primaryKeyName</span> <span class="hljs-operator">=</span> primaryKeys.getString(<span class="hljs-string">&quot;COLUMN_NAME&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">primaryKeySeq</span> <span class="hljs-operator">=</span> primaryKeys.getString(<span class="hljs-string">&quot;KEY_SEQ&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">primaryKeyTableName</span> <span class="hljs-operator">=</span> primaryKeys.getString(<span class="hljs-string">&quot;TABLE_NAME&quot;</span>);<br>            <span class="hljs-comment">// 输出主键信息</span><br>            System.out.println(<span class="hljs-string">&quot;Primary Key Name: &quot;</span> + primaryKeyName);<br>            System.out.println(<span class="hljs-string">&quot;Primary Key Sequence: &quot;</span> + primaryKeySeq);<br>            System.out.println(<span class="hljs-string">&quot;Primary Key Table Name: &quot;</span> + primaryKeyTableName);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="表结构"><a href="#表结构" class="headerlink" title="表结构"></a>表结构</h1><p>创建名为 test 数据库，执行以下 sql 语句创建 user 表。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `<span class="hljs-keyword">user</span>` (<br>  `id` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;主键&#x27;</span>,<br>  `name` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;名称&#x27;</span>,<br>  `pwd` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;密码&#x27;</span>,<br>  `create_date` datetime <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">UPDATE</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,<br>  `update_date` datetime <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;更新时间&#x27;</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)<br>) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;用户表&#x27;</span>;<br></code></pre></td></tr></table></figure><h1 id="项目结构"><a href="#项目结构" class="headerlink" title="项目结构"></a>项目结构</h1><p><img src="/images/spring-boot-code-generator.jpg"></p><pre><code class="hljs">spring-boot-code-generator│├─src│  ├─main│  │  ├─java│  │  │  └─com│  │  │      └─example│  │  │          └─codegenerator│  │  │              │  SpringBootCodeGeneratorApplication.java│  │  │              ││  │  │              ├─common│  │  │              │      BaseDao.java│  │  │              │      BaseDaoImpl.java│  │  │              │      Page.java│  │  │              │      ResultModel.java│  │  │              ││  │  │              ├─config│  │  │              │      DataSourceConfig.java│  │  │              ││  │  │              ├─constant│  │  │              │      DbConstant.java│  │  │              │      TemplateConstant.java│  │  │              ││  │  │              ├─param│  │  │              │      ColumnParam.java│  │  │              │      TableParam.java│  │  │              │      TemplatePathParam.java│  │  │              ││  │  │              └─utils│  │  │                      CodeGenerateUtils.java│  │  │                      DbUtils.java│  │  │                      FreeMarkerTemplateUtils.java│  │  │                      StrUtils.java│  │  ││  │  └─resources│  │      │  application.properties│  │      ││  │      └─templates│  │              controller.ftl│  │              dao.ftl│  │              entity.ftl│  │              param.ftl│  │              service.ftl│  │              serviceImpl.ftl│  ││  └─test│      └─java│          └─com│              └─example│                  └─codegenerator│                          SpringBootCodeGeneratorApplicationTests.java</code></pre><h1 id="依赖配置"><a href="#依赖配置" class="headerlink" title="依赖配置"></a>依赖配置</h1><p>在项目的 pom.xml 的 dependencies 中导入需要的依赖包:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.freemarker<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>freemarker<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.3.31<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>$&#123;mysql.version&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cn.hutool<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hutool-all<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.8.5<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.commons<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>commons-lang3<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.8.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.hibernate.javax.persistence<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hibernate-jpa-2.1-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0.2.Final<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.hibernate<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hibernate-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.6.9.Final<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-orm<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.22<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure><h1 id="全局配置"><a href="#全局配置" class="headerlink" title="全局配置"></a>全局配置</h1><p>在项目的 application.properties 文件里添加所需配置：</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">spring.datasource.username</span>=<span class="hljs-string">root</span><br><span class="hljs-attr">spring.datasource.password</span>=<span class="hljs-string">root</span><br><span class="hljs-attr">spring.datasource.url</span>=<span class="hljs-string">jdbc:mysql://localhost:3306/test?serverTimezone=UTC&amp;setUnicode=true&amp;charterEncoding=utf-8</span><br><span class="hljs-attr">spring.datasource.driver-class-name</span>=<span class="hljs-string">com.mysql.cj.jdbc.Driver</span><br></code></pre></td></tr></table></figure><h1 id="编码"><a href="#编码" class="headerlink" title="编码"></a>编码</h1><h2 id="1、常量类"><a href="#1、常量类" class="headerlink" title="1、常量类"></a>1、常量类</h2><h3 id="1-1、数据库常量"><a href="#1-1、数据库常量" class="headerlink" title="1.1、数据库常量"></a>1.1、数据库常量</h3><ul><li><p>该类定义了三个数组常量：<code>COLUMNTYPE_TIME</code>、<code>COLUMNTYPE_NUMBER</code>，分别用于存储数据库时间类型和数字类型。</p></li><li><p>还定义了四个字符串常量：<code>TYPE_STRING</code>、<code>TYPE_INTEGER</code>、<code>TYPE_LONG</code> 和 <code>TYPE_BIGDECIMAL</code>，用于表示不同类型的数据。</p></li><li><p>例如，<code>TYPE_STRING</code> 表示字符串类型，<code>TYPE_INTEGER</code> 表示整型，<code>TYPE_LONG</code> 表示长整型，<code>TYPE_BIGDECIMAL</code> 表示高精度计算类型。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.constant;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DbConstant</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 数据库时间类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String[] COLUMNTYPE_TIME = &#123;<span class="hljs-string">&quot;datetime&quot;</span>, <span class="hljs-string">&quot;time&quot;</span>, <span class="hljs-string">&quot;date&quot;</span>, <span class="hljs-string">&quot;timestamp&quot;</span>&#125;;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 数据库数字类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String[] COLUMNTYPE_NUMBER = &#123;<span class="hljs-string">&quot;tinyint&quot;</span>, <span class="hljs-string">&quot;smallint&quot;</span>, <span class="hljs-string">&quot;mediumint&quot;</span>, <span class="hljs-string">&quot;int&quot;</span>, <span class="hljs-string">&quot;number&quot;</span>, <span class="hljs-string">&quot;integer&quot;</span>,<br>            <span class="hljs-string">&quot;bit&quot;</span>, <span class="hljs-string">&quot;bigint&quot;</span>, <span class="hljs-string">&quot;float&quot;</span>, <span class="hljs-string">&quot;double&quot;</span>, <span class="hljs-string">&quot;decimal&quot;</span>&#125;;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 字符串类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">TYPE_STRING</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;String&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 整型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">TYPE_INTEGER</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Integer&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 长整型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">TYPE_LONG</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Long&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 高精度计算类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">TYPE_BIGDECIMAL</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;BigDecimal&quot;</span>;<br><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 时间类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">TYPE_DATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Date&quot;</span>;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h3 id="1-2、模板常量"><a href="#1-2、模板常量" class="headerlink" title="1.2、模板常量"></a>1.2、模板常量</h3><ul><li><p>该类中包含了几个静态常量，这些常量定义了一些模板的文件路径。通过这些常量，可以引用不同的模板文件。</p></li><li><p>例如，<code>ENTITY_TEMPLATE</code> 常量指向了一个实体类的模板文件，<code>DAO_TEMPLATE</code> 常量指向了 dao 的模板文件，以此类推。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.constant;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TemplateConstant</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 实体类模板</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">ENTITY_TEMPLATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;templates/entity.ftl&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * dao模板</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">DAO_TEMPLATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;templates/dao.ftl&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * param模板</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">PARAM_TEMPLATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;templates/param.ftl&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * service模版</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">SERVICE_TEMPLATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;templates/service.ftl&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * service实现类模版</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">SERVICE_IMPL_TEMPLATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;templates/serviceImpl.ftl&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * controller模版</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">CONTROLLER_TEMPLATE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;templates/controller.ftl&quot;</span>;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="2、参数类"><a href="#2、参数类" class="headerlink" title="2、参数类"></a>2、参数类</h2><h3 id="2-1、字段参数"><a href="#2-1、字段参数" class="headerlink" title="2.1、字段参数"></a>2.1、字段参数</h3><ul><li><p>该类用于封装从数据库表中读取的字段信息。</p></li><li><p>该类包含了字段名、字段类型、字段注释、主键信息以及 Java 类型等信息。</p></li><li><p>通过这些信息，可以在后续的代码生成过程中使用这些信息。</p></li><li><p>例如，在生成实体类时，可以使用字段名、字段类型以及 Java 类型来生成对应的属性和 getter&#x2F;setter 方法。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.param;<br><br><span class="hljs-keyword">import</span> lombok.Data;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ColumnParam</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 数据库字段名称</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String columnName;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 数据库字段类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String columnType;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 数据库字段首字母小写且去掉下划线字符串</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String changeColumnName;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 数据库字段注释</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String columnComment;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 主键</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String primaryKey;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * java 类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String javaType;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h3 id="2-2、表参数"><a href="#2-2、表参数" class="headerlink" title="2.2、表参数"></a>2.2、表参数</h3><ul><li><p>该类用于封装从数据库表中读取的表信息。</p></li><li><p>该类包含了表名、表注释、表中数据的日期时间格式、是否包含日期字段、是否包含浮点型字段以及表主键类型等信息。</p></li><li><p>通过这些信息，可以在后续的代码生成过程中使用这些信息。</p></li><li><p>例如，在生成实体类时，可以根据表主键类型来生成对应的主键属性。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.param;<br><br><span class="hljs-keyword">import</span> lombok.Data;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TableParam</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 表名</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String tableName;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 表注释</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String tableComment;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 日期时间格式化模式</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">String</span> <span class="hljs-variable">datePattern</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 是否存在日期</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">boolean</span> exitDate;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 是否存在浮点型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">boolean</span> exitBigDecimal;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 表主键类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String primaryKeyType;<br><br>&#125;<br><br></code></pre></td></tr></table></figure></details><h3 id="2-3、模板参数"><a href="#2-3、模板参数" class="headerlink" title="2.3、模板参数"></a>2.3、模板参数</h3><ul><li><p>该类用于封装代码生成过程中需要使用的一些路径信息。</p></li><li><p>该类包含了包名、项目名称、作者、生成代码的基础路径以及各个模板文件生成的绝对路径等信息。</p></li><li><p>通过这些信息，可以在后续的代码生成过程中使用这些信息。</p></li><li><p>例如，在生成实体类时，可以使用实体类生成的绝对路径来指定实体类文件的存储路径。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.param;<br><br><span class="hljs-keyword">import</span> lombok.Data;<br><span class="hljs-keyword">import</span> org.apache.commons.lang3.StringUtils;<br><br><span class="hljs-keyword">import</span> java.text.SimpleDateFormat;<br><span class="hljs-keyword">import</span> java.util.Date;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The type Template path param.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TemplatePathParam</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">String</span> <span class="hljs-variable">currentDate</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleDateFormat</span>(<span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>).format(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>());<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 包名</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String packageName;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 代码生成路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String basePath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 项目名称</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String projectName;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 作者</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String author;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 实体类生成的绝对路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String entityPath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * dao生成的绝对路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String daoPath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * param生成的绝对路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String paramPath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * service接口生成的绝对路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String servicePath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * service实现类生成的绝对路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String serviceImplPath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * controller生成的绝对路径</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> String controllerPath;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> packageName 包名</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> basePath    生成代码的基础路径</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> projectName 项目名称</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> author      作者</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">TemplatePathParam</span><span class="hljs-params">(String packageName, String basePath, String projectName, String author)</span> &#123;<br>        <span class="hljs-keyword">if</span> (StringUtils.isBlank(packageName)<br>                || StringUtils.isBlank(basePath)<br>                || StringUtils.isBlank(author)) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(<span class="hljs-string">&quot;参数不能为空&quot;</span>);<br>        &#125;<br>        <span class="hljs-built_in">this</span>.packageName = packageName;<br>        <span class="hljs-built_in">this</span>.basePath = basePath;<br>        <span class="hljs-built_in">this</span>.author = author;<br>        <span class="hljs-built_in">this</span>.projectName = projectName;<br><br>        String[] split = packageName.split(<span class="hljs-string">&quot;\\.&quot;</span>);<br><br>        StringBuilder javaModelPath;<br>        <span class="hljs-keyword">if</span> (StringUtils.isBlank(projectName)) &#123;<br>            javaModelPath = <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>(basePath + <span class="hljs-string">&quot;\\src\\main\\java\\&quot;</span>);<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            javaModelPath = <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>(basePath + <span class="hljs-string">&quot;\\&quot;</span> + projectName + <span class="hljs-string">&quot;\\src\\main\\java\\&quot;</span>);<br>        &#125;<br><br>        <span class="hljs-keyword">for</span> (String s : split) &#123;<br>            javaModelPath.append(s);<br>            javaModelPath.append(<span class="hljs-string">&quot;\\&quot;</span>);<br>        &#125;<br>        <span class="hljs-built_in">this</span>.setEntityPath(javaModelPath + <span class="hljs-string">&quot;\\entity&quot;</span>);<br>        <span class="hljs-built_in">this</span>.setDaoPath(javaModelPath + <span class="hljs-string">&quot;\\dao&quot;</span>);<br>        <span class="hljs-built_in">this</span>.setParamPath(javaModelPath + <span class="hljs-string">&quot;\\param&quot;</span>);<br>        <span class="hljs-built_in">this</span>.setServicePath(javaModelPath + <span class="hljs-string">&quot;\\service&quot;</span>);<br>        <span class="hljs-built_in">this</span>.setServiceImplPath(javaModelPath + <span class="hljs-string">&quot;\\service\\impl&quot;</span>);<br>        <span class="hljs-built_in">this</span>.setControllerPath(javaModelPath + <span class="hljs-string">&quot;\\controller&quot;</span>);<br>    &#125;<br><br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="3、工具类"><a href="#3、工具类" class="headerlink" title="3、工具类"></a>3、工具类</h2><h3 id="3-1、代码生成器工具类"><a href="#3-1、代码生成器工具类" class="headerlink" title="3.1、代码生成器工具类"></a>3.1、代码生成器工具类</h3><ul><li><p>该类主要用于根据给定的 FreeMarker 模板和数据模型生成代码。<code>generate()</code> 方法接受表名作为输入，并从数据库中检索相应的表信息。然后，它使用此信息基于指定的 FreeMarker 模板为应用程序的不同层生成代码（例如实体，DAO，服务，控制器）。</p></li><li><p>生成的代码写入指定的输出目录中的文件系统。该类期望模板位于 classpath 目录下，并使用 <code>FreeMarkerTemplateUtils</code> 类加载模板。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.utils;<br><br><span class="hljs-keyword">import</span> com.example.codegenerator.constant.TemplateConstant;<br><span class="hljs-keyword">import</span> com.example.codegenerator.param.ColumnParam;<br><span class="hljs-keyword">import</span> com.example.codegenerator.param.TableParam;<br><span class="hljs-keyword">import</span> com.example.codegenerator.param.TemplatePathParam;<br><span class="hljs-keyword">import</span> freemarker.template.Template;<br><span class="hljs-keyword">import</span> org.apache.commons.lang3.StringUtils;<br><br><span class="hljs-keyword">import</span> java.io.*;<br><span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;<br><span class="hljs-keyword">import</span> java.util.HashMap;<br><span class="hljs-keyword">import</span> java.util.List;<br><span class="hljs-keyword">import</span> java.util.Map;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 代码生成器入口</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CodeGenerateUtils</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">TemplatePathParam</span> <span class="hljs-variable">templatePathParam</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">CodeGenerateUtils</span> <span class="hljs-variable">codeGenerateUtils</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">CodeGenerateUtils</span>();<br>        codeGenerateUtils.templatePathParam = <span class="hljs-keyword">new</span> <span class="hljs-title class_">TemplatePathParam</span>(<span class="hljs-string">&quot;com.example.codegenerator.modules.test&quot;</span>,<br>                <span class="hljs-string">&quot;D:\\study\\spring-boot-demo\\spring-boot-code-generator&quot;</span>,<br>                <span class="hljs-string">&quot;&quot;</span>,<br>                <span class="hljs-string">&quot;loquy&quot;</span>);<br>        codeGenerateUtils.generate(<span class="hljs-string">&quot;user&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generate</span><span class="hljs-params">(String tableName)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">//数据库相关</span><br>        <span class="hljs-type">DbUtils</span> <span class="hljs-variable">dbUtil</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DbUtils</span>();<br>        List&lt;TableParam&gt; allTables = dbUtil.getAllTables(tableName);<br>        <span class="hljs-keyword">if</span> (allTables.get(<span class="hljs-number">0</span>).getTableName() == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-comment">//获取所有表</span><br>            List&lt;TableParam&gt; allTable = dbUtil.getAllTables(<span class="hljs-string">&quot;&quot;</span>);<br>            <span class="hljs-keyword">for</span> (TableParam tableClass : allTable) &#123;<br>                generateOne(dbUtil, tableClass);<br>            &#125;<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            generateOne(dbUtil, allTables.get(<span class="hljs-number">0</span>));<br>        &#125;<br><br>        dbUtil.closeConnection();<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateOne</span><span class="hljs-params">(DbUtils dbUtil, TableParam tableClass)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">//表名</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">table</span> <span class="hljs-operator">=</span> tableClass.getTableName();<br>        <span class="hljs-comment">//获取所有列</span><br>        List&lt;ColumnParam&gt; allColumns = dbUtil.getAllColumns(table);<br><br>        <span class="hljs-type">boolean</span> <span class="hljs-variable">date</span> <span class="hljs-operator">=</span> allColumns.stream().anyMatch(m -&gt; <span class="hljs-string">&quot;Date&quot;</span>.equals(m.getJavaType()));<br>        <span class="hljs-type">boolean</span> <span class="hljs-variable">bigDecimal</span> <span class="hljs-operator">=</span> allColumns.stream().anyMatch(m -&gt; <span class="hljs-string">&quot;BigDecimal&quot;</span>.equals(m.getJavaType()));<br>        <span class="hljs-type">ColumnParam</span> <span class="hljs-variable">columnParam</span> <span class="hljs-operator">=</span> allColumns.stream().filter(m -&gt; m.getColumnName().equals(m.getPrimaryKey())).findFirst().orElse(<span class="hljs-literal">null</span>);<br><br>        tableClass.setExitDate(date);<br>        tableClass.setExitBigDecimal(bigDecimal);<br>        tableClass.setPrimaryKeyType(<span class="hljs-string">&quot;String&quot;</span>);<br>        <span class="hljs-keyword">if</span> (columnParam != <span class="hljs-literal">null</span>) &#123;<br>            tableClass.setPrimaryKeyType(columnParam.getJavaType());<br>        &#125;<br><br>        System.out.println(<span class="hljs-string">&quot;============正在生成 &quot;</span> + table + <span class="hljs-string">&quot; 表相关文件============&quot;</span>);<br><br>        <span class="hljs-comment">//生成实体类</span><br>        System.out.println(<span class="hljs-string">&quot;生成 entity 类&quot;</span>);<br>        generateEntityFile(tableClass, allColumns);<br><br>        <span class="hljs-comment">//生成dao层文件</span><br>        System.out.println(<span class="hljs-string">&quot;生成 dao 类&quot;</span>);<br>        generateDaoFile(tableClass);<br><br>        <span class="hljs-comment">//生成param参数类</span><br>        System.out.println(<span class="hljs-string">&quot;生成 param 类&quot;</span>);<br>        generateParamFile(tableClass, allColumns);<br><br>        <span class="hljs-comment">//生成service接口</span><br>        System.out.println(<span class="hljs-string">&quot;生成 service 接口&quot;</span>);<br>        generateServiceFile(tableClass);<br><br>        <span class="hljs-comment">//生成service实现类</span><br>        System.out.println(<span class="hljs-string">&quot;生成 service 实现类&quot;</span>);<br>        generateServiceImplFile(tableClass);<br><br>        <span class="hljs-comment">//生成Controller层文件</span><br>        System.out.println(<span class="hljs-string">&quot;生成 controller 类&quot;</span>);<br>        generateControllerFile(tableClass);<br><br>        System.out.println(<span class="hljs-string">&quot;============ 全部生成完成！ =============&quot;</span>);<br>    &#125;<br><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 生成实体文件</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateEntityFile</span><span class="hljs-params">(TableParam tableClass, List&lt;ColumnParam&gt; allColumns)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;.java&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> templatePathParam.getEntityPath();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> templatePathParam.getEntityPath() + <span class="hljs-string">&quot;\\&quot;</span> + StrUtils.changeTableStr(tableClass.getTableName()) + suffix;<br><br>        Map&lt;String, Object&gt; dataMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">6</span>);<br>        dataMap.put(<span class="hljs-string">&quot;model_column&quot;</span>, allColumns);<br>        dataMap = getCommonModel(dataMap, tableClass);<br>        generateFileByTemplate(TemplateConstant.ENTITY_TEMPLATE, filePath, file, dataMap);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 生成dao层文件</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateDaoFile</span><span class="hljs-params">(TableParam tableClass)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Dao.java&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> templatePathParam.getDaoPath();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> templatePathParam.getDaoPath() + <span class="hljs-string">&quot;\\&quot;</span> + StrUtils.changeTableStr(tableClass.getTableName()) + suffix;<br><br>        Map&lt;String, Object&gt; dataMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">6</span>);<br>        dataMap = getCommonModel(dataMap, tableClass);<br>        generateFileByTemplate(TemplateConstant.DAO_TEMPLATE, filePath, file, dataMap);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 生成参数类</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateParamFile</span><span class="hljs-params">(TableParam tableClass, List&lt;ColumnParam&gt; allColumns)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Param.java&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> templatePathParam.getParamPath();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> templatePathParam.getParamPath() + <span class="hljs-string">&quot;\\&quot;</span> + StrUtils.changeTableStr(tableClass.getTableName()) + suffix;<br><br>        Map&lt;String, Object&gt; dataMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">6</span>);<br>        dataMap.put(<span class="hljs-string">&quot;model_column&quot;</span>, allColumns);<br>        dataMap = getCommonModel(dataMap, tableClass);<br>        generateFileByTemplate(TemplateConstant.PARAM_TEMPLATE, filePath, file, dataMap);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 生成业务接口层</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateServiceFile</span><span class="hljs-params">(TableParam tableClass)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Service.java&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> templatePathParam.getServicePath();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> templatePathParam.getServicePath() + <span class="hljs-string">&quot;\\&quot;</span> + StrUtils.changeTableStr(tableClass.getTableName()) + suffix;<br><br>        Map&lt;String, Object&gt; dataMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">6</span>);<br>        dataMap = getCommonModel(dataMap, tableClass);<br>        generateFileByTemplate(TemplateConstant.SERVICE_TEMPLATE, filePath, file, dataMap);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 生成业务实现层</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateServiceImplFile</span><span class="hljs-params">(TableParam tableClass)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;ServiceImpl.java&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> templatePathParam.getServiceImplPath();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> templatePathParam.getServiceImplPath() + <span class="hljs-string">&quot;\\&quot;</span> + StrUtils.changeTableStr(tableClass.getTableName()) + suffix;<br><br>        Map&lt;String, Object&gt; dataMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">6</span>);<br>        dataMap = getCommonModel(dataMap, tableClass);<br>        generateFileByTemplate(TemplateConstant.SERVICE_IMPL_TEMPLATE, filePath, file, dataMap);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 生成控制层</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateControllerFile</span><span class="hljs-params">(TableParam tableClass)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;Controller.java&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> templatePathParam.getControllerPath();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> templatePathParam.getControllerPath() + <span class="hljs-string">&quot;\\&quot;</span> + StrUtils.changeTableStr(tableClass.getTableName()) + suffix;<br><br>        Map&lt;String, Object&gt; dataMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">6</span>);<br>        dataMap = getCommonModel(dataMap, tableClass);<br>        generateFileByTemplate(TemplateConstant.CONTROLLER_TEMPLATE, filePath, file, dataMap);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 模版通用参数</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> dataMap    模型map</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> tableClass 表名和表注释参数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Map&lt;String, Object&gt; <span class="hljs-title function_">getCommonModel</span><span class="hljs-params">(Map&lt;String, Object&gt; dataMap, TableParam tableClass)</span> &#123;<br>        dataMap.put(<span class="hljs-string">&quot;table_name&quot;</span>, StrUtils.changeTableStr(tableClass.getTableName()));<br>        dataMap.put(<span class="hljs-string">&quot;table_name_small&quot;</span>, StrUtils.changeColumnStr(tableClass.getTableName()));<br>        dataMap.put(<span class="hljs-string">&quot;table&quot;</span>, tableClass.getTableName());<br>        dataMap.put(<span class="hljs-string">&quot;datePattern&quot;</span>, tableClass.getDatePattern());<br>        dataMap.put(<span class="hljs-string">&quot;exitDate&quot;</span>, tableClass.isExitDate());<br>        dataMap.put(<span class="hljs-string">&quot;exitBigDecimal&quot;</span>, tableClass.isExitBigDecimal());<br>        dataMap.put(<span class="hljs-string">&quot;author&quot;</span>, templatePathParam.getAuthor());<br>        dataMap.put(<span class="hljs-string">&quot;date&quot;</span>, templatePathParam.getCurrentDate());<br>        dataMap.put(<span class="hljs-string">&quot;package_name&quot;</span>, templatePathParam.getPackageName());<br>        dataMap.put(<span class="hljs-string">&quot;project_name&quot;</span>, templatePathParam.getProjectName());<br>        dataMap.put(<span class="hljs-string">&quot;table_annotation&quot;</span>, StringUtils.isNotBlank(tableClass.getTableComment()) ? tableClass.getTableComment() : <span class="hljs-literal">null</span>);<br>        <span class="hljs-keyword">return</span> dataMap;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 静态化方法</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> templateName  模版名称</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> filePathParam 文件所在目录 绝对路径</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> fileParam     文件 绝对路径</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> dataMap       数据模型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">generateFileByTemplate</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String templateName,</span><br><span class="hljs-params">                                        String filePathParam,</span><br><span class="hljs-params">                                        String fileParam,</span><br><span class="hljs-params">                                        Map&lt;String, Object&gt; dataMap)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">Template</span> <span class="hljs-variable">template</span> <span class="hljs-operator">=</span> FreeMarkerTemplateUtils.getTemplate(templateName);<br>        System.out.println(fileParam);<br>        <span class="hljs-comment">//文件夹不存在创建文件夹</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">filePath</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(filePathParam);<br>        <span class="hljs-keyword">if</span> (!filePath.exists() &amp;&amp; !filePath.isDirectory()) &#123;<br>            <span class="hljs-type">boolean</span> <span class="hljs-variable">mkdirs</span> <span class="hljs-operator">=</span> filePath.mkdirs();<br>            <span class="hljs-keyword">if</span> (!mkdirs) &#123;<br>                System.out.println(filePathParam + <span class="hljs-string">&quot;创建失败！&quot;</span>);<br>            &#125;<br>        &#125;<br>        <span class="hljs-comment">//文件不存在创建文件夹</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(fileParam);<br>        <span class="hljs-keyword">if</span> (!file.exists()) &#123;<br>            <span class="hljs-keyword">try</span> &#123;<br>                <span class="hljs-type">boolean</span> <span class="hljs-variable">newFile</span> <span class="hljs-operator">=</span> file.createNewFile();<br>                <span class="hljs-keyword">if</span> (!newFile) &#123;<br>                    System.out.println(fileParam + <span class="hljs-string">&quot;创建失败！&quot;</span>);<br>                &#125;<br>            &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>                e.printStackTrace();<br>            &#125;<br>        &#125;<br>        <span class="hljs-type">FileOutputStream</span> <span class="hljs-variable">fos</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(file);<br>        <span class="hljs-type">Writer</span> <span class="hljs-variable">out</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedWriter</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">OutputStreamWriter</span>(fos, StandardCharsets.UTF_8), <span class="hljs-number">10240</span>);<br>        template.process(dataMap, out);<br>    &#125;<br><br>&#125;<br><br></code></pre></td></tr></table></figure></details><h3 id="3-2、数据库工具类"><a href="#3-2、数据库工具类" class="headerlink" title="3.2、数据库工具类"></a>3.2、数据库工具类</h3><ul><li><p>该类主要用于连接数据库、获取数据库信息，如表名、字段名、字段类型等，并封装成对象返回。</p></li><li><p>该类中主要用到了 JDBC 连接数据库的 API，包括 <code>DriverManager.getConnection()</code> 方法用于获取数据库连接，<code>DatabaseMetaData</code> 类中的方法用于获取数据库元数据信息。</p></li><li><p>其中 <code>getAllTables()</code> 方法用于获取所有表名及注释，<code>getAllColumns()</code> 方法用于获取某张表的所有列信息，<code>getJavaType()</code> 方法用于将数据库字段类型转换成 Java 类型。</p></li><li><p>需要注意的是，该类中使用到的配置信息，例如数据库链接地址、用户名、密码等，需要通过读取 <code>application.properties</code> 文件获取，读取文件使用了第三方库 <code>hutool</code> 的 Props 类。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.utils;<br><br><span class="hljs-keyword">import</span> cn.hutool.setting.dialect.Props;<br><span class="hljs-keyword">import</span> com.example.codegenerator.constant.DbConstant;<br><span class="hljs-keyword">import</span> com.example.codegenerator.param.ColumnParam;<br><span class="hljs-keyword">import</span> com.example.codegenerator.param.TableParam;<br><span class="hljs-keyword">import</span> org.apache.commons.lang3.StringUtils;<br><br><span class="hljs-keyword">import</span> java.sql.*;<br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.Arrays;<br><span class="hljs-keyword">import</span> java.util.List;<br><span class="hljs-keyword">import</span> java.util.Properties;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 数据库工具类</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DbUtils</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Props</span> <span class="hljs-variable">props</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Props</span>(<span class="hljs-string">&quot;application.properties&quot;</span>);<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">url</span> <span class="hljs-operator">=</span> getProps().getProperty(<span class="hljs-string">&quot;spring.datasource.url&quot;</span>);<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> getProps().getProperty(<span class="hljs-string">&quot;spring.datasource.username&quot;</span>);<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">password</span> <span class="hljs-operator">=</span> getProps().getProperty(<span class="hljs-string">&quot;spring.datasource.password&quot;</span>);<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">driver</span> <span class="hljs-operator">=</span> getProps().getProperty(<span class="hljs-string">&quot;spring.datasource.driver-class-name&quot;</span>);<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">Connection</span> <span class="hljs-variable">connection</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取jdbc链接</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Connection <span class="hljs-title function_">getConnection</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">Properties</span> <span class="hljs-variable">pro</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Properties</span>();<br>        pro.setProperty(<span class="hljs-string">&quot;user&quot;</span>, username);<br>        pro.setProperty(<span class="hljs-string">&quot;password&quot;</span>, password);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">mysql</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;mysql&quot;</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">oracle</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;oracle&quot;</span>;<br>        <span class="hljs-keyword">if</span> (url.contains(mysql)) &#123;<br>            <span class="hljs-comment">//获取mysql表注释</span><br>            pro.setProperty(<span class="hljs-string">&quot;useInformationSchema&quot;</span>, <span class="hljs-string">&quot;true&quot;</span>);<br>        &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (url.contains(oracle)) &#123;<br>            <span class="hljs-comment">//获取oracle表注释</span><br>            pro.setProperty(<span class="hljs-string">&quot;remarksReporting&quot;</span>, <span class="hljs-string">&quot;true&quot;</span>);<br>        &#125;<br><br>        Class.forName(driver);<br>        connection = DriverManager.getConnection(url, pro);<br>        <span class="hljs-keyword">return</span> connection;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取当前数据库下的所有表名称及注释</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> List&lt;TableParam&gt; <span class="hljs-title function_">getAllTables</span><span class="hljs-params">(String table)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">tableName</span> <span class="hljs-operator">=</span> StringUtils.isNotEmpty(table) ? table : <span class="hljs-string">&quot;%&quot;</span>;<br>        List&lt;TableParam&gt; list = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        <span class="hljs-comment">//获取链接</span><br>        <span class="hljs-type">Connection</span> <span class="hljs-variable">conn</span> <span class="hljs-operator">=</span> getConnection();<br>        <span class="hljs-comment">//获取元数据</span><br>        <span class="hljs-type">DatabaseMetaData</span> <span class="hljs-variable">metaData</span> <span class="hljs-operator">=</span> conn.getMetaData();<br>        <span class="hljs-comment">//获取所有的数据库表信息</span><br>        <span class="hljs-type">ResultSet</span> <span class="hljs-variable">rs</span> <span class="hljs-operator">=</span> metaData.getTables(conn.getCatalog(), <span class="hljs-string">&quot;%&quot;</span>, tableName, <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>[]&#123;<span class="hljs-string">&quot;TABLE&quot;</span>&#125;);<br>        <span class="hljs-keyword">while</span> (rs.next()) &#123;<br>            <span class="hljs-type">TableParam</span> <span class="hljs-variable">tableClass</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TableParam</span>();<br>            tableClass.setTableName(rs.getString(<span class="hljs-number">3</span>));<br>            tableClass.setTableComment(rs.getString(<span class="hljs-number">5</span>));<br>            list.add(tableClass);<br>        &#125;<br><br>        <span class="hljs-keyword">if</span> (list.size() == <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(tableName + <span class="hljs-string">&quot;表不存在！&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">return</span> list;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取某张表的所有列</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> List&lt;ColumnParam&gt; <span class="hljs-title function_">getAllColumns</span><span class="hljs-params">(String tableName)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        List&lt;ColumnParam&gt; list = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        <span class="hljs-comment">//获取链接</span><br>        <span class="hljs-type">Connection</span> <span class="hljs-variable">conn</span> <span class="hljs-operator">=</span> getConnection();<br>        <span class="hljs-comment">//获取元数据</span><br>        <span class="hljs-type">DatabaseMetaData</span> <span class="hljs-variable">metaData</span> <span class="hljs-operator">=</span> conn.getMetaData();<br>        <span class="hljs-comment">//获取所有的数据库某张表所有列信息</span><br>        <span class="hljs-type">ResultSet</span> <span class="hljs-variable">rs</span> <span class="hljs-operator">=</span> metaData.getColumns(conn.getCatalog(), <span class="hljs-string">&quot;%&quot;</span>, tableName, <span class="hljs-string">&quot;%&quot;</span>);<br>        <span class="hljs-comment">//获取主键字段</span><br>        <span class="hljs-type">ResultSet</span> <span class="hljs-variable">rsPk</span> <span class="hljs-operator">=</span> metaData.getPrimaryKeys(conn.getCatalog(), <span class="hljs-literal">null</span>, tableName);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">primaryKey</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span>;<br>        <span class="hljs-keyword">while</span> (rsPk.next()) &#123;<br>            primaryKey = rsPk.getString(<span class="hljs-string">&quot;COLUMN_NAME&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">while</span> (rs.next()) &#123;<br>            <span class="hljs-type">ColumnParam</span> <span class="hljs-variable">columnClass</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ColumnParam</span>();<br>            columnClass.setPrimaryKey(primaryKey);<br>            columnClass.setColumnName(rs.getString(<span class="hljs-string">&quot;COLUMN_NAME&quot;</span>));<br>            columnClass.setColumnType(rs.getString(<span class="hljs-string">&quot;TYPE_NAME&quot;</span>));<br>            columnClass.setJavaType(getJavaType(rs.getString(<span class="hljs-string">&quot;TYPE_NAME&quot;</span>)));<br>            columnClass.setColumnComment(rs.getString(<span class="hljs-string">&quot;REMARKS&quot;</span>));<br>            columnClass.setChangeColumnName(StrUtils.changeColumnStr(rs.getString(<span class="hljs-string">&quot;COLUMN_NAME&quot;</span>)));<br>            list.add(columnClass);<br>        &#125;<br><br>        <span class="hljs-keyword">if</span> (list.size() == <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(tableName + <span class="hljs-string">&quot;表不存在！&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">return</span> list;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取数据库表字段类型对应的java类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getJavaType</span><span class="hljs-params">(String columnType)</span> &#123;<br>        columnType = columnType.toLowerCase();<br>        <span class="hljs-type">String</span> <span class="hljs-variable">dataType</span> <span class="hljs-operator">=</span> getDbType(columnType);<br>        <span class="hljs-keyword">if</span> (arraysContains(DbConstant.COLUMNTYPE_TIME, dataType)) &#123;<br>            <span class="hljs-comment">// 时间类型</span><br>            <span class="hljs-keyword">return</span> DbConstant.TYPE_DATE;<br>        &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (arraysContains(DbConstant.COLUMNTYPE_NUMBER, dataType)) &#123;<br>            String[] str = StringUtils.split(StringUtils.substringBetween(columnType, <span class="hljs-string">&quot;(&quot;</span>, <span class="hljs-string">&quot;)&quot;</span>), <span class="hljs-string">&quot;,&quot;</span>);<br>            <span class="hljs-keyword">if</span> (str != <span class="hljs-literal">null</span> &amp;&amp; str.length == <span class="hljs-number">2</span> &amp;&amp; Integer.parseInt(str[<span class="hljs-number">1</span>]) &gt; <span class="hljs-number">0</span>) &#123;<br>                <span class="hljs-comment">// 如果是浮点型 统一用BigDecimal</span><br>                <span class="hljs-keyword">return</span> DbConstant.TYPE_BIGDECIMAL;<br>            &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (str != <span class="hljs-literal">null</span> &amp;&amp; str.length == <span class="hljs-number">1</span> &amp;&amp; Integer.parseInt(str[<span class="hljs-number">0</span>]) &lt;= <span class="hljs-number">10</span>) &#123;<br>                <span class="hljs-comment">// 如果是整形</span><br>                <span class="hljs-keyword">return</span> DbConstant.TYPE_INTEGER;<br>            &#125;<span class="hljs-keyword">else</span> &#123;<br>                <span class="hljs-comment">// 长整形</span><br>                <span class="hljs-keyword">return</span> DbConstant.TYPE_LONG;<br>            &#125;<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-comment">// 字符串</span><br>            <span class="hljs-keyword">return</span> DbConstant.TYPE_STRING;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 校验数组是否包含指定值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> arr         数组</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> targetValue 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 是否包含</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">arraysContains</span><span class="hljs-params">(String[] arr, String targetValue)</span> &#123;<br>        <span class="hljs-keyword">return</span> Arrays.asList(arr).contains(targetValue);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取数据库类型字段</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> columnType 列类型</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 截取后的列类型</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">getDbType</span><span class="hljs-params">(String columnType)</span><br>    &#123;<br>        <span class="hljs-keyword">if</span> (StringUtils.indexOf(columnType, <span class="hljs-string">&quot;(&quot;</span>) &gt; <span class="hljs-number">0</span>)<br>        &#123;<br>            <span class="hljs-keyword">return</span> StringUtils.substringBefore(columnType, <span class="hljs-string">&quot;(&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">else</span><br>        &#123;<br>            <span class="hljs-keyword">return</span> columnType;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 关闭链接</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">closeConnection</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            connection.close();<br>        &#125; <span class="hljs-keyword">catch</span> (SQLException e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> Props <span class="hljs-title function_">getProps</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> props;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h3 id="3-3、FreeMarker-工具类"><a href="#3-3、FreeMarker-工具类" class="headerlink" title="3.3、FreeMarker 工具类"></a>3.3、FreeMarker 工具类</h3><ul><li><p>该类用于加载并获取 FreeMarker 模板文件。</p></li><li><p>FreeMarker 是一种模板引擎，可以通过模板文件来生成静态文本，模板文件中可以使用 FreeMarker 的指令和数据变量来动态控制文本的生成。</p></li><li><p><code>FreeMarkerTemplateUtils</code> 类中，<code>CONFIGURATION</code> 对象表示一个 FreeMarker 模板配置，该对象用于设置 FreeMarker 的各种属性，包括模板文件的加载方式、编码方式、异常处理方式等。</p></li><li><p><code>getTemplate()</code> 方法用于根据模板文件名称获取一个 <code>Template</code> 对象，该对象表示一个 FreeMarker 模板文件，可以通过它来生成静态文本。</p></li><li><p>在这个工具类中，模板文件的加载方式采用的是 <code>FileTemplateLoader</code> 类，即从 classpath 目录下加载模板文件。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.utils;<br><br><span class="hljs-keyword">import</span> freemarker.cache.FileTemplateLoader;<br><span class="hljs-keyword">import</span> freemarker.cache.NullCacheStorage;<br><span class="hljs-keyword">import</span> freemarker.template.Configuration;<br><span class="hljs-keyword">import</span> freemarker.template.Template;<br><span class="hljs-keyword">import</span> freemarker.template.TemplateExceptionHandler;<br><br><span class="hljs-keyword">import</span> java.io.File;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><span class="hljs-keyword">import</span> java.util.Objects;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * FreeMarker模版工具类</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FreeMarkerTemplateUtils</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">FreeMarkerTemplateUtils</span><span class="hljs-params">()</span> &#123;<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Configuration</span> <span class="hljs-variable">CONFIGURATION</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Configuration</span>(Configuration.VERSION_2_3_22);<br><br>    <span class="hljs-keyword">static</span> &#123;<br>        <span class="hljs-comment">//ClassTemplateLoader方式：需要将模版放在FreeMarkerTemplateUtils类所在的包，加载模版时会从该包下加载</span><br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> java.net.URLDecoder.decode(Objects.requireNonNull(<br>                    FreeMarkerTemplateUtils.class.getClassLoader().getResource(<span class="hljs-string">&quot;&quot;</span>)).getPath(), <span class="hljs-string">&quot;utf-8&quot;</span>);<br>            <span class="hljs-comment">//FileTemplateLoader方式：需要将模版放置在classpath目录下 目录有中文也可以</span><br>            CONFIGURATION.setTemplateLoader(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileTemplateLoader</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path)));<br>        &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>        CONFIGURATION.setDefaultEncoding(<span class="hljs-string">&quot;UTF-8&quot;</span>);<br>        CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);<br>        CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Template <span class="hljs-title function_">getTemplate</span><span class="hljs-params">(String templateName)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br>        <span class="hljs-keyword">return</span> CONFIGURATION.getTemplate(templateName);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h3 id="3-4、字符串工具类"><a href="#3-4、字符串工具类" class="headerlink" title="3.4、字符串工具类"></a>3.4、字符串工具类</h3><ul><li><p>该类包含两个方法：<code>changeColumnStr</code> 和 <code>changeTableStr</code>。</p></li><li><p><code>changeColumnStr</code> 方法用于将一个带下划线的字符串转换为驼峰命名法，例如将 “user_name” 转换为 “userName”。</p></li><li><p><code>changeTableStr</code> 方法用于将一个带下划线的字符串转换为驼峰命名法，并且首字母大写，例如将 “tb_user” 转换为 “TbUser”。</p></li><li><p>两个方法都会通过递归调用来处理多个下划线的情况。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.codegenerator.utils;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 字符串处理工具类</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">StrUtils</span> &#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 去掉下划线转驼峰  user_name  -&gt; userName</span><br><span class="hljs-comment">     */</span><br>     <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">changeColumnStr</span><span class="hljs-params">(String str)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">name</span> <span class="hljs-operator">=</span> str;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">underline</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;_&quot;</span>;<br>        <span class="hljs-keyword">if</span> (name.indexOf(underline) &gt; <span class="hljs-number">0</span> &amp;&amp; name.length() != name.indexOf(underline) + <span class="hljs-number">1</span>) &#123;<br>            <span class="hljs-type">int</span> <span class="hljs-variable">lengthPlace</span> <span class="hljs-operator">=</span> name.indexOf(underline);<br>            name = name.replaceFirst(underline, <span class="hljs-string">&quot;&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">s</span> <span class="hljs-operator">=</span> name.substring(lengthPlace, lengthPlace + <span class="hljs-number">1</span>);<br>            s = s.toUpperCase();<br>            str = name.substring(<span class="hljs-number">0</span>, lengthPlace) + s + name.substring(lengthPlace + <span class="hljs-number">1</span>);<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-keyword">return</span> str;<br>        &#125;<br>        <span class="hljs-keyword">return</span> changeColumnStr(str);<br>     &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 去掉下划线转驼峰  tb_user  -&gt; TbUser</span><br><span class="hljs-comment">     */</span><br>     <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">changeTableStr</span><span class="hljs-params">(String str)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">s</span> <span class="hljs-operator">=</span> changeColumnStr(str);<br>        <span class="hljs-keyword">return</span> s.substring(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>).toUpperCase() + s.substring(<span class="hljs-number">1</span>);<br>     &#125;<br>  &#125;<br><br></code></pre></td></tr></table></figure></details><h1 id="制作通用模板"><a href="#制作通用模板" class="headerlink" title="制作通用模板"></a>制作通用模板</h1><p>在 resources&#x2F;templates 目录下创建模版文件，模板内容可自定义成你所需要的。</p><h2 id="1、entity-模版"><a href="#1、entity-模版" class="headerlink" title="1、entity 模版"></a>1、entity 模版</h2><ul><li><p>该模板中使用了 Freemarker 模板语言的语法，通过传入的参数（例如表名、字段信息等）来生成对应的实体类代码。</p></li><li><p>例如，在模板中可以使用 <code>$&#123;package_name&#125;</code> 来表示包名，使用 <code>$&#123;table_name&#125;</code> 来表示实体类名称，使用 <code>$&#123;model_column&#125;</code> 来表示表中所有的字段信息。</p></li><li><p>通过这些变量，可以生成完整的实体类代码。例如，通过循环遍历 <code>$&#123;model_column&#125;</code> 中的每一个字段信息，可以生成对应的属性和 getter&#x2F;setter 方法。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> $&#123;package_name&#125;.entity;<br><br><span class="hljs-keyword">import</span> javax.persistence.Entity;<br><span class="hljs-keyword">import</span> javax.persistence.Table;<br><span class="hljs-keyword">import</span> javax.persistence.Column;<br><span class="hljs-keyword">import</span> javax.persistence.Id;<br>&lt;#<span class="hljs-keyword">if</span> exitBigDecimal&gt;<br><span class="hljs-keyword">import</span> java.math.BigDecimal;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br>&lt;#<span class="hljs-keyword">if</span> exitDate&gt;<br><span class="hljs-keyword">import</span> java.util.Date;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.annotation.JsonFormat;<br><span class="hljs-keyword">import</span> org.springframework.format.annotation.DateTimeFormat;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br><span class="hljs-keyword">import</span> java.io.Serializable;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">* &lt;#if table_annotation??&gt;$&#123;table_annotation&#125;&lt;/#if&gt;Entity</span><br><span class="hljs-comment">* <span class="hljs-doctag">@author</span> $&#123;author&#125;</span><br><span class="hljs-comment">* <span class="hljs-doctag">@date</span> $&#123;date&#125;</span><br><span class="hljs-comment">*/</span><br><span class="hljs-meta">@Entity</span><br><span class="hljs-meta">@Table(name = &quot;$&#123;table&#125;&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">$</span>&#123;table_name&#125; <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span> &#123;<br>&lt;#<span class="hljs-keyword">if</span> model_column?exists&gt;<br>    &lt;#list model_column as model&gt;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * $&#123;model.columnComment!&#125;</span><br><span class="hljs-comment">    */</span><br>    &lt;#<span class="hljs-keyword">if</span> (model.primaryKey! = model.columnName)&gt;<br>    <span class="hljs-meta">@Id</span><br>    <span class="hljs-meta">@Column(name = &quot;$&#123;model.columnName?uncap_first&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> $&#123;model.javaType&#125; $&#123;model.changeColumnName?uncap_first&#125;;<br><br>    &lt;#<span class="hljs-keyword">else</span>&gt;<br>    <span class="hljs-meta">@Column(name = &quot;$&#123;model.columnName?uncap_first&#125;&quot;)</span><br>    &lt;#<span class="hljs-keyword">if</span> model.javaType == <span class="hljs-string">&#x27;Date&#x27;</span>&gt;<br>    <span class="hljs-meta">@JsonFormat(pattern = &quot;$&#123;datePattern&#125;&quot;, timezone = &quot;GMT+8&quot;)</span><br>    <span class="hljs-meta">@DateTimeFormat(pattern = &quot;$&#123;datePattern&#125;&quot;)</span><br>    &lt;/#<span class="hljs-keyword">if</span>&gt;<br>    <span class="hljs-keyword">private</span> $&#123;model.javaType&#125; $&#123;model.changeColumnName?uncap_first&#125;;<br><br>    &lt;/#<span class="hljs-keyword">if</span>&gt;<br>    &lt;/#list&gt;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br>&lt;#<span class="hljs-keyword">if</span> model_column?exists&gt;<br>    &lt;#list model_column as model&gt;<br>    <span class="hljs-keyword">public</span> $&#123;model.javaType&#125; get$&#123;model.changeColumnName?cap_first &#125;() &#123;<br>        <span class="hljs-keyword">return</span> $&#123;model.changeColumnName&#125;;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> set$&#123;model.changeColumnName?cap_first &#125;($&#123;model.javaType&#125; $&#123;model.changeColumnName?uncap_first &#125;) &#123;<br>        <span class="hljs-built_in">this</span>.$&#123;model.changeColumnName&#125; = $&#123;model.changeColumnName&#125;;<br>    &#125;<br><br>    &lt;/#list&gt;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="2、dao-模板"><a href="#2、dao-模板" class="headerlink" title="2、dao 模板"></a>2、dao 模板</h2><ul><li><p>该模板中使用了 Freemarker 模板语言的语法，通过传入的参数（例如包名、实体类名等）来生成对应的 Dao 类代码。</p></li><li><p>该 Dao 类继承自 <code>BaseDaoImpl</code>，并在构造函数中调用父类的构造函数传入实体类的类型，以便在操作数据库时获取到实体类的信息。</p></li><li><p>该 Dao 类还使用了 <code>@Repository</code> 注解，用于将该类标识为 Spring 的数据访问对象。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> $&#123;package_name&#125;.dao;<br><br><span class="hljs-keyword">import</span> com.example.codegenerator.common.BaseDaoImpl;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.entity.$&#123;table_name&#125;;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Repository;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">* &lt;#if table_annotation??&gt;$&#123;table_annotation&#125;&lt;/#if&gt;Dao</span><br><span class="hljs-comment">* <span class="hljs-doctag">@author</span> $&#123;author&#125;</span><br><span class="hljs-comment">* <span class="hljs-doctag">@date</span> $&#123;date&#125;</span><br><span class="hljs-comment">*/</span><br><span class="hljs-meta">@Repository</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;Dao <span class="hljs-keyword">extends</span> <span class="hljs-title class_">BaseDaoImpl</span>&lt;$&#123;table_name&#125;&gt; &#123;<br>    <span class="hljs-keyword">public</span> $&#123;table_name&#125;Dao() &#123;<br>        <span class="hljs-built_in">super</span>($&#123;table_name&#125;.class);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="3、param-模板"><a href="#3、param-模板" class="headerlink" title="3、param 模板"></a>3、param 模板</h2><ul><li><p>该模板中使用了 Freemarker 模板语言的语法，通过传入的参数（例如包名、表名等）来生成对应的查询参数类代码。</p></li><li><p>该查询参数类实现了 <code>Serializable</code> 接口，表示该类的对象可以被序列化。</p></li><li><p>该查询参数类中定义了与数据库表中列名相同的属性，并提供了对应的 getter 和 setter 方法。</p></li><li><p>该类还使用了 <code>@JsonFormat</code> 和 <code>@DateTimeFormat</code> 注解来格式化日期类型的属性。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> $&#123;package_name&#125;.param;<br><br><span class="hljs-keyword">import</span> java.io.Serializable;<br>&lt;#<span class="hljs-keyword">if</span> exitBigDecimal&gt;<br>    <span class="hljs-keyword">import</span> java.math.BigDecimal;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br>&lt;#<span class="hljs-keyword">if</span> exitDate&gt;<br><span class="hljs-keyword">import</span> java.util.Date;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.annotation.JsonFormat;<br><span class="hljs-keyword">import</span> org.springframework.format.annotation.DateTimeFormat;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">* &lt;#if table_annotation??&gt;$&#123;table_annotation&#125;&lt;/#if&gt;Param</span><br><span class="hljs-comment">* <span class="hljs-doctag">@author</span> $&#123;author&#125;</span><br><span class="hljs-comment">* <span class="hljs-doctag">@date</span> $&#123;date&#125;</span><br><span class="hljs-comment">*/</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;Param <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span> &#123;<br>&lt;#<span class="hljs-keyword">if</span> model_column?exists&gt;<br>    &lt;#list model_column as model&gt;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * $&#123;model.columnComment!&#125;</span><br><span class="hljs-comment">    */</span><br>    &lt;#<span class="hljs-keyword">if</span> model.javaType == <span class="hljs-string">&#x27;Date&#x27;</span>&gt;<br>    <span class="hljs-meta">@JsonFormat(pattern = &quot;$&#123;datePattern&#125;&quot;, timezone = &quot;GMT+8&quot;)</span><br>    <span class="hljs-meta">@DateTimeFormat(pattern = &quot;$&#123;datePattern&#125;&quot;)</span><br>    &lt;/#<span class="hljs-keyword">if</span>&gt;<br>    <span class="hljs-keyword">private</span> $&#123;model.javaType&#125; $&#123;model.changeColumnName?uncap_first&#125;;<br><br>    &lt;/#list&gt;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br>&lt;#<span class="hljs-keyword">if</span> model_column?exists&gt;<br>    &lt;#list model_column as model&gt;<br>    <span class="hljs-keyword">public</span> $&#123;model.javaType&#125; get$&#123;model.changeColumnName?cap_first &#125;() &#123;<br>        <span class="hljs-keyword">return</span> $&#123;model.changeColumnName&#125;;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> set$&#123;model.changeColumnName?cap_first &#125;($&#123;model.javaType&#125; $&#123;model.changeColumnName?uncap_first &#125;) &#123;<br>        <span class="hljs-built_in">this</span>.$&#123;model.changeColumnName&#125; = $&#123;model.changeColumnName&#125;;<br>    &#125;<br><br>    &lt;/#list&gt;<br>&lt;/#<span class="hljs-keyword">if</span>&gt;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="4、service-模版"><a href="#4、service-模版" class="headerlink" title="4、service 模版"></a>4、service 模版</h2><ul><li><p>这段代码定义了一个接口，用于创建一个服务类，该服务类可以可以用来对名为 <code>$&#123;table_name&#125;</code> 的实体执行 CRUD（创建、读取、更新、删除）操作。</p></li><li><p>该服务暴露了几个方法，例如 <code>list</code>、<code>getById</code>、<code>save</code>、<code>updateById</code> 和 <code>removeById</code>，</p></li><li><p>它们分别允许用户获取实体列表、根据 ID 获取单个实体、创建新实体、更新现有实体和删除实体。</p></li><li><p>服务方法都会返回一个 <code>ResultModel</code> 对象，其中包含操作结果。</p></li><li><p><code>ResultModel</code> 类是一个自定义类，它提供了一种统一的方式来表示应用程序中操作的结果。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> $&#123;package_name&#125;.service;<br><br><span class="hljs-keyword">import</span> com.example.codegenerator.common.Page;<br><span class="hljs-keyword">import</span> com.example.codegenerator.common.ResultModel;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.entity.$&#123;table_name&#125;;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">* &lt;#if table_annotation??&gt;$&#123;table_annotation&#125;&lt;/#if&gt;Service</span><br><span class="hljs-comment">* <span class="hljs-doctag">@author</span> $&#123;author&#125;</span><br><span class="hljs-comment">* <span class="hljs-doctag">@date</span> $&#123;date&#125;</span><br><span class="hljs-comment">*/</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;Service &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 查询所有</span><br><span class="hljs-comment">    *</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> page the page</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment">    */</span><br>    ResultModel&lt;Page&lt;$&#123;table_name&#125;&gt;&gt; list(Page&lt;$&#123;table_name&#125;&gt; page);<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 查询一个</span><br><span class="hljs-comment">    *</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id the id</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> the by id</span><br><span class="hljs-comment">    */</span><br>    ResultModel&lt;$&#123;table_name&#125;&gt; getById(Object id);<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 新增</span><br><span class="hljs-comment">    *</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> $&#123;table_name_small&#125; the $&#123;table_name_small&#125;</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> the boolean</span><br><span class="hljs-comment">    */</span><br>    ResultModel&lt;Object&gt; <span class="hljs-title function_">save</span><span class="hljs-params">($&#123;table_name&#125; $&#123;table_name_small&#125;)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 修改</span><br><span class="hljs-comment">    *</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> $&#123;table_name_small&#125; the $&#123;table_name_small&#125;</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> the boolean</span><br><span class="hljs-comment">    */</span><br>    ResultModel&lt;Object&gt; <span class="hljs-title function_">updateById</span><span class="hljs-params">($&#123;table_name&#125; $&#123;table_name_small&#125;)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 删除</span><br><span class="hljs-comment">    *</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id the id</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> the boolean</span><br><span class="hljs-comment">    */</span><br>    ResultModel&lt;Object&gt; <span class="hljs-title function_">removeById</span><span class="hljs-params">(Object id)</span>;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="5、service-实现类模版"><a href="#5、service-实现类模版" class="headerlink" title="5、service 实现类模版"></a>5、service 实现类模版</h2><ul><li><p>这段代码定义了一个前面定义的 <code>$&#123;table_name&#125;Service</code> 接口的具体实现。</p></li><li><p>该类使用了 <code>@Service</code> 和 <code>@Transactional</code> 注解，表示它是一个 Spring 服务 Bean ，并且它使用了 Spring 框架的事务支持。</p></li><li><p>这意味着这个类中使用了 <code>@Transactional</code> 注解的任何方法都将在数据库事务中执行。</p></li><li><p>该类的构造函数接收一个 <code>$&#123;table_name&#125;Dao</code> 实例，这个实例可能是一个数据访问对象（DAO）类，用于对 <code>$&#123;table_name&#125;</code> 实体执行数据库操作。</p></li><li><p>该类实现了 <code>$&#123;table_name&#125;Service</code> 接口定义的方法，为每个方法提供了具体的实现。</p></li><li><p>例如，<code>list</code> 方法使用 DAO 执行一个 SQL 查询，从数据库中使用提供的 <code>Page</code> 对象分页来检索 <code>$&#123;table_name&#125;</code> 实体的列表。</p></li><li><p>然后该方法返回一个包含实体列表的 <code>ResultModel</code> 对象。</p></li><li><p>类中的其他方法也都使用了 DAO 来在数据库中对 <code>$&#123;table_name&#125;</code> 实体执行 CRUD 操作，并返回一个包含操作结果的 <code>ResultModel</code> 对象。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> $&#123;package_name&#125;.service.impl;<br><br><span class="hljs-keyword">import</span> com.example.codegenerator.common.Page;<br><span class="hljs-keyword">import</span> com.example.codegenerator.common.ResultModel;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.entity.$&#123;table_name&#125;;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.service.$&#123;table_name&#125;Service;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.dao.$&#123;table_name&#125;Dao;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Service;<br><span class="hljs-keyword">import</span> org.springframework.transaction.annotation.Transactional;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">* &lt;#if table_annotation??&gt;$&#123;table_annotation&#125;&lt;/#if&gt;ServiceImpl</span><br><span class="hljs-comment">* <span class="hljs-doctag">@author</span> $&#123;author&#125;</span><br><span class="hljs-comment">* <span class="hljs-doctag">@date</span> $&#123;date&#125;</span><br><span class="hljs-comment">*/</span><br><span class="hljs-meta">@Service</span><br><span class="hljs-meta">@Transactional(rollbackFor = Exception.class)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;ServiceImpl <span class="hljs-keyword">implements</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;Service&#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> $&#123;table_name&#125;Dao $&#123;table_name_small&#125;Dao;<br><br>    <span class="hljs-keyword">public</span> $&#123;table_name&#125;ServiceImpl($&#123;table_name&#125;Dao $&#123;table_name_small&#125;Dao) &#123;<br>        <span class="hljs-built_in">this</span>.$&#123;table_name_small&#125;Dao = $&#123;table_name_small&#125;Dao;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Page&lt;$&#123;table_name&#125;&gt;&gt; list(Page&lt;$&#123;table_name&#125;&gt; page) &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">sql</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;select * from $&#123;table_name_small&#125;&quot;</span>;<br>        <span class="hljs-keyword">return</span> ResultModel.success($&#123;table_name_small&#125;Dao.getNativeQueryListByPage(sql, page));<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;$&#123;table_name&#125;&gt; getById(Object id) &#123;<br>        <span class="hljs-keyword">return</span> ResultModel.success($&#123;table_name_small&#125;Dao.findOne(id));<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Object&gt; <span class="hljs-title function_">save</span><span class="hljs-params">($&#123;table_name&#125; $&#123;table_name_small&#125;)</span> &#123;<br>        $&#123;table_name&#125; $&#123;table_name_small&#125;Old = $&#123;table_name_small&#125;Dao.findOne($&#123;table_name_small&#125;.getId());<br>        <span class="hljs-keyword">if</span> ($&#123;table_name_small&#125;Old == <span class="hljs-literal">null</span>) &#123;<br>            $&#123;table_name_small&#125;Dao.insert($&#123;table_name_small&#125;);<br>            <span class="hljs-keyword">return</span> ResultModel.success(<span class="hljs-string">&quot;保存成功！&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">return</span> ResultModel.fail(<span class="hljs-string">&quot;已存在数据，保存失败！&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Object&gt; <span class="hljs-title function_">updateById</span><span class="hljs-params">($&#123;table_name&#125; $&#123;table_name_small&#125;)</span> &#123;<br>        $&#123;table_name&#125; $&#123;table_name_small&#125;Old = $&#123;table_name_small&#125;Dao.findOne($&#123;table_name_small&#125;.getId());<br>        <span class="hljs-keyword">if</span> ($&#123;table_name_small&#125;Old != <span class="hljs-literal">null</span>) &#123;<br>            $&#123;table_name_small&#125;Dao.update($&#123;table_name_small&#125;);<br>            <span class="hljs-keyword">return</span> ResultModel.success();<br>        &#125;<br>        <span class="hljs-keyword">return</span> ResultModel.fail(<span class="hljs-string">&quot;更新失败！&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Object&gt; <span class="hljs-title function_">removeById</span><span class="hljs-params">(Object id)</span> &#123;<br>        $&#123;table_name&#125; $&#123;table_name_small&#125; = $&#123;table_name_small&#125;Dao.findOne(id);<br>        <span class="hljs-keyword">if</span> ($&#123;table_name_small&#125; != <span class="hljs-literal">null</span>) &#123;<br>            $&#123;table_name_small&#125;Dao.delete($&#123;table_name_small&#125;);<br>            <span class="hljs-keyword">return</span> ResultModel.success();<br>        &#125;<br>        <span class="hljs-keyword">return</span> ResultModel.fail(<span class="hljs-string">&quot;删除失败！&quot;</span>);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h2 id="6、controller-模版"><a href="#6、controller-模版" class="headerlink" title="6、controller 模版"></a>6、controller 模版</h2><ul><li><p>这段代码是一个 Java 控制器，它提供了一系列用于管理 <code>$&#123;table_name&#125;</code> 实体的 RESTful API 接口。</p></li><li><p>具体来说，它提供了以下接口：</p><ul><li><p><code>/list</code>：用于获取 <code>$&#123;table_name&#125;</code> 实体的分页列表。</p></li><li><p><code>/read/&#123;id&#125;</code>：用于获取一个 <code>$&#123;table_name&#125;</code> 实体的详细信息。</p></li><li><p><code>/create</code>：用于新建 <code>$&#123;table_name&#125;</code> 实体。</p></li><li><p><code>/update</code>：用于更新 <code>$&#123;table_name&#125;</code> 实体。</p></li><li><p><code>/delete/&#123;id&#125;</code>：用于删除 <code>$&#123;table_name&#125;</code> 实体。</p></li></ul></li><li><p>该控制器使用 <code>@RestController</code> 注解声明了它是一个 RESTful 控制器，并通过 <code>@RequestMapping(&quot;/$&#123;table_name_small&#125;&quot;)</code> 注解指定了它的基础路径为 <code>/$&#123;table_name_small&#125;</code>。</p></li><li><p>除了接口的基础路径之外，每个接口还有一个方法级别的路径。例如，新增接口的完整路径为 <code>/$&#123;table_name_small&#125;/create</code>。</p></li><li><p>每个接口都有一个对应的方法，该方法实现了接口的具体逻辑。每个方法都通过 <code>@GetMapping</code>、<code>@PostMapping</code> 或 <code>@DeleteMapping</code> 注解来指定它的 HTTP 方法和路径。</p></li><li><p>该控制器还使用了 <code>@Validated</code> 和 <code>@PathVariable</code> 注解，分别用于对参数进行验证和从路径中获取参数值。</p></li></ul><details>  <summary>点击查看代码</summary><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> $&#123;package_name&#125;.controller;<br><br><span class="hljs-keyword">import</span> com.example.codegenerator.common.Page;<br><span class="hljs-keyword">import</span> com.example.codegenerator.common.ResultModel;<br><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;<br><span class="hljs-keyword">import</span> org.springframework.beans.BeanUtils;<br><span class="hljs-keyword">import</span> org.springframework.validation.annotation.Validated;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.entity.$&#123;table_name&#125;;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.param.$&#123;table_name&#125;Param;<br><span class="hljs-keyword">import</span> $&#123;package_name&#125;.service.$&#123;table_name&#125;Service;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * &lt;#if table_annotation??&gt;$&#123;table_annotation&#125;&lt;/#if&gt;Controller</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> $&#123;author&#125;</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> $&#123;date&#125;</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@RestController</span><br><span class="hljs-meta">@RequestMapping(&quot;/$&#123;table_name_small&#125;&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;Controller &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> $&#123;table_name&#125;Service $&#123;table_name_small&#125;Service;<br><br>    <span class="hljs-keyword">public</span> $&#123;table_name&#125;Controller($&#123;table_name&#125;Service $&#123;table_name_small&#125;Service) &#123;<br>        <span class="hljs-built_in">this</span>.$&#123;table_name_small&#125;Service = $&#123;table_name_small&#125;Service;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 查询所有</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@GetMapping(&quot;/list&quot;)</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Page&lt;$&#123;table_name&#125;&gt;&gt; list(<span class="hljs-meta">@RequestParam(value = &quot;currentPage&quot;)</span> Integer currentPage,<br>            <span class="hljs-meta">@RequestParam(value = &quot;pageSize&quot;)</span> Integer pageSize) &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            Page&lt;$&#123;table_name&#125;&gt; page = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Page</span>&lt;&gt;(currentPage, pageSize);<br>            <span class="hljs-keyword">return</span> $&#123;table_name_small&#125;Service.list(page);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> ResultModel.fail(e.getMessage());<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 查询一个</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@GetMapping(&quot;read/&#123;id&#125;&quot;)</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;$&#123;table_name&#125;&gt; get(<span class="hljs-meta">@PathVariable</span> $&#123;primaryKeyType&#125; id) &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> $&#123;table_name_small&#125;Service.getById(id);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> ResultModel.fail(e.getMessage());<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 新增</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@PostMapping(&quot;/create&quot;)</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Object&gt; <span class="hljs-title function_">save</span><span class="hljs-params">(<span class="hljs-meta">@Validated</span> <span class="hljs-meta">@RequestBody</span> $&#123;table_name&#125;Param $&#123;table_name_small&#125;Param)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            $&#123;table_name&#125; $&#123;table_name_small&#125; = <span class="hljs-keyword">new</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;();<br>            BeanUtils.copyProperties($&#123;table_name_small&#125;Param, $&#123;table_name_small&#125;);<br>            <span class="hljs-keyword">return</span> $&#123;table_name_small&#125;Service.save($&#123;table_name_small&#125;);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> ResultModel.fail(e.getMessage());<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 修改</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@PostMapping(&quot;/update&quot;)</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Object&gt; <span class="hljs-title function_">update</span><span class="hljs-params">(<span class="hljs-meta">@Validated</span> <span class="hljs-meta">@RequestBody</span> $&#123;table_name&#125;Param $&#123;table_name_small&#125;Param)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            $&#123;table_name&#125; $&#123;table_name_small&#125; = <span class="hljs-keyword">new</span> <span class="hljs-title class_">$</span>&#123;table_name&#125;();<br>            BeanUtils.copyProperties($&#123;table_name_small&#125;Param, $&#123;table_name_small&#125;);<br>            <span class="hljs-keyword">return</span> $&#123;table_name_small&#125;Service.updateById($&#123;table_name_small&#125;);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> ResultModel.fail(e.getMessage());<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 删除</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@PostMapping(&quot;/delete/&#123;id&#125;&quot;)</span><br>    <span class="hljs-keyword">public</span> ResultModel&lt;Object&gt; <span class="hljs-title function_">delete</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> $&#123;primaryKeyType&#125; id)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> $&#123;table_name_small&#125;Service.removeById(id);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> ResultModel.fail(e.getMessage());<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure></details><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><ul><li>执行代码生成器工具类 <code>CodeGenerateUtils</code> 输出如下。</li></ul><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs text">============正在生成 user 表相关文件============<br>生成 entity 类<br>D:\study\spring-boot-demo\spring-boot-code-generator\src\main\java\com\example\codegenerator\modules\test\\entity\User.java<br>生成 dao 类<br>D:\study\spring-boot-demo\spring-boot-code-generator\src\main\java\com\example\codegenerator\modules\test\\dao\UserDao.java<br>生成 param 类<br>D:\study\spring-boot-demo\spring-boot-code-generator\src\main\java\com\example\codegenerator\modules\test\\param\UserParam.java<br>生成 service 接口<br>D:\study\spring-boot-demo\spring-boot-code-generator\src\main\java\com\example\codegenerator\modules\test\\service\UserService.java<br>生成 service 实现类<br>D:\study\spring-boot-demo\spring-boot-code-generator\src\main\java\com\example\codegenerator\modules\test\\service\impl\UserServiceImpl.java<br>生成 controller 类<br>D:\study\spring-boot-demo\spring-boot-code-generator\src\main\java\com\example\codegenerator\modules\test\\controller\UserController.java<br>============ 全部生成完成！ =============<br></code></pre></td></tr></table></figure><ul><li>文件创建成功，相关模块文件如下。</li></ul><p><img src="/images/codeGenFiles.jpg"></p><ul><li>启动项目测试刚生成的模块接口是否正常，调用增删改查接口如下。</li></ul><p><img src="/images/codeGenList.jpg"><br><img src="/images/codeGenRead.jpg"><br><img src="/images/codeGenCreate.jpg"><br><img src="/images/codeGenDelete.jpg"></p><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p><a href="https://github.com/loquy/spring-boot-demo">参见此仓库</a></p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span><a href="https://yun.itheima.com/jishu/419.html?bilibi">自定义代码生成器</a><a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:2" class="footnote-text"><span><a href="https://segmentfault.com/a/1190000011768799">FreeMarker 快速入门</a><a href="#fnref:2" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:3" class="footnote-text"><span><a href="https://blog.csdn.net/niugang0920/article/details/119530050">使用 JDBC 提取数据库元数据</a><a href="#fnref:3" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;代码生成器的主要目的是提高开发效率，减少重复劳动，并确保生成的代码符合一定的规范。

可以使用它来</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="FreeMarker" scheme="http://www.loquy.cn/tags/FreeMarker/"/>
    
  </entry>
  
  <entry>
    <title>Java 日期和时间</title>
    <link href="http://www.loquy.cn/posts/8ce0f8c6.html"/>
    <id>http://www.loquy.cn/posts/8ce0f8c6.html</id>
    <published>2022-11-18T09:43:00.000Z</published>
    <updated>2022-11-18T09:43:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>Java 提供了两套日期和时间的接口。</p><ol><li><p>旧版：<code>Date</code>、<code>Calendar</code> 等，<code>Date</code> 类主要封装了系统的日期和时间的信息，<code>Calendar</code> 类则会根据系统的日历来解释 <code>Date</code> 对象。</p></li><li><p>从 Java 8 开始，<code>java.time</code> 包提供了新的日期和时间 API，主要涉及的类有：</p><ul><li>本地日期和时间：<code>LocalDateTime</code>，<code>LocalDate</code>，<code>LocalTime</code>；</li><li>带时区的日期和时间：<code>ZonedDateTime</code>；</li><li>时刻：<code>Instant</code>；</li><li>时区：<code>ZoneId</code>，<code>ZoneOffset</code>；</li><li>时间间隔：<code>Duration</code>。</li></ul><p>以及一套新的用于取代 <code>SimpleDateFormat</code> 的格式化类 <code>DateTimeFormatter</code>。和旧的 API 相比，新 API 严格区分了时刻、本地日期、本地时间和带时区的日期时间，并且对日期和时间进行运算更加方便。新 API 的类型几乎全部是不变类型（和 String 类似），可以放心使用不必担心被修改。</p></li><li><p><code>SimpleDateFormat</code> 是线程不安全的类，一般不要定义为 static 变量，如果定义为 static，必须加锁，或者使用 <code>DateUtils</code> 工具类。 正例：注意线程安全，使用 <code>DateUtils</code>。亦推荐如下处理：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> ThreadLocal&lt;DateFormat&gt; df = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ThreadLocal</span>&lt;DateFormat&gt;() &#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> DateFormat <span class="hljs-title function_">initialValue</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleDateFormat</span>(<span class="hljs-string">&quot;yyyy-MM-dd&quot;</span>);<br>    &#125;<br>&#125;;<br></code></pre></td></tr></table></figure><p>说明：如果是 JDK8 的应用，可以使用 <code>Instant</code> 代替 <code>Date</code>，<code>LocalDateTime</code> 代替 <code>Calendar</code>，<code>DateTimeFormatter</code> 代替  <code>SimpleDateFormat</code>，官方给出的解释：simple beautiful strong immutable thread-safe。——引用《阿里巴巴Java开发手册》</p></li><li><p>日期和时间类相关的操作方法用到时查询即可，无需记忆，用着用着就熟悉了。</p></li></ol><h1 id="格式化模式"><a href="#格式化模式" class="headerlink" title="格式化模式"></a>格式化模式</h1><table><thead><tr><th>字母</th><th>含义</th><th>示例</th></tr></thead><tbody><tr><td>y</td><td>年份</td><td>使用 yy 表示的年份，如 11； 使用 yyyy 表示的年份，如 2011</td></tr><tr><td>M</td><td>月份</td><td>使用 MM 表示的月份，如 05； 使用 MMM 表示月份，在 Locale.CHINA 语言环境下，如“十月”；在 Locale.US 语言环境下，如 Oct</td></tr><tr><td>d</td><td>月份中的天数</td><td>使用 dd 表示的天数，如 10</td></tr><tr><td>D</td><td>年份中的天数</td><td>使用 D 表示的年份中的天数，如 360</td></tr><tr><td>E</td><td>星期几</td><td>使用 E 表示星期几，在 Locale.CHINA 语言环境下，如“星期四”；在 Locale.US 语 言环境下，如 Thu</td></tr><tr><td>H</td><td>一天中的小时数（0~23)</td><td>使用 HH 表示的小时数，如 18</td></tr><tr><td>h</td><td>一天中的小时数（1~12)</td><td>使用 hh 表示的小时数，如 10 (注意 10 有 可能是 10 点，也可能是 22 点）</td></tr><tr><td>m</td><td>分钟数</td><td>使用 mm 表示的分钟数，如 29</td></tr><tr><td>s</td><td>秒数</td><td>使用 ss 表示的秒数，如 38</td></tr><tr><td>S</td><td>毫秒数</td><td>使用 SSS 表示的毫秒数，如 156</td></tr></tbody></table><h1 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h1><h2 id="日期和字符串相互转换"><a href="#日期和字符串相互转换" class="headerlink" title="日期和字符串相互转换"></a>日期和字符串相互转换</h2><ul><li>旧版</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">dateToStr</span><span class="hljs-params">(Date date)</span> &#123;<br>    <span class="hljs-type">SimpleDateFormat</span> <span class="hljs-variable">sdf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleDateFormat</span>(<span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>);<br>    <span class="hljs-keyword">return</span> sdf.format(date);<br>&#125;<br></code></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Date <span class="hljs-title function_">strToDate</span><span class="hljs-params">(String strDate)</span> <span class="hljs-keyword">throws</span> ParseException &#123;<br>    <span class="hljs-type">SimpleDateFormat</span> <span class="hljs-variable">sdf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleDateFormat</span>(<span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>);<br>    <span class="hljs-keyword">return</span> sdf.parse(strDate);<br>&#125;<br></code></pre></td></tr></table></figure><ul><li>Java 8</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">localDateTimeToStr</span><span class="hljs-params">(LocalDateTime localDateTime)</span> &#123;<br>    <span class="hljs-type">DateTimeFormatter</span> <span class="hljs-variable">dateTimeFormatter</span> <span class="hljs-operator">=</span> DateTimeFormatter.ofPattern(<span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>);<br>    <span class="hljs-keyword">return</span> localDateTime.format(dateTimeFormatter);<br>&#125;<br></code></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> LocalDateTime <span class="hljs-title function_">strToLocalDateTime</span><span class="hljs-params">(String strDate)</span>&#123;<br>    <span class="hljs-type">DateTimeFormatter</span> <span class="hljs-variable">dateTimeFormatter</span> <span class="hljs-operator">=</span> DateTimeFormatter.ofPattern(<span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>);<br>    <span class="hljs-keyword">return</span> LocalDateTime.parse(strDate, dateTimeFormatter);<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="LocalDateTime-和-Date-相互转换"><a href="#LocalDateTime-和-Date-相互转换" class="headerlink" title="LocalDateTime 和 Date 相互转换"></a>LocalDateTime 和 Date 相互转换</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> LocalDateTime <span class="hljs-title function_">dateToLocalDateTime</span><span class="hljs-params">(Date date)</span>&#123;<br>    <span class="hljs-keyword">return</span> date.toInstant()<br>        <span class="hljs-comment">//设置当前系统时区</span><br>        .atZone(ZoneId.systemDefault())<br>        .toLocalDateTime();<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Date <span class="hljs-title function_">localDateTimeToDate</span><span class="hljs-params">(LocalDateTime localDateTime)</span>&#123;<br>    <span class="hljs-keyword">return</span> Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="获取当天零点"><a href="#获取当天零点" class="headerlink" title="获取当天零点"></a>获取当天零点</h2><ul><li>旧版</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Date <span class="hljs-title function_">getTodayZeroByDate</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-type">Calendar</span> <span class="hljs-variable">calendar</span> <span class="hljs-operator">=</span> Calendar.getInstance();<br>    calendar.setTime(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>());<br>    calendar.set(Calendar.HOUR_OF_DAY, <span class="hljs-number">0</span>);<br>    calendar.set(Calendar.MINUTE, <span class="hljs-number">0</span>);<br>    calendar.set(Calendar.SECOND, <span class="hljs-number">0</span>);<br>    <span class="hljs-keyword">return</span> calendar.getTime();<br>&#125;<br></code></pre></td></tr></table></figure><ul><li>Java 8</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> LocalDateTime <span class="hljs-title function_">getTodayZeroByLocalDateTime</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-type">LocalDateTime</span> <span class="hljs-variable">now</span> <span class="hljs-operator">=</span> LocalDateTime.now();<br>    <span class="hljs-comment">// 当天的 00:00</span><br>    <span class="hljs-keyword">return</span> LocalDateTime.of(now.toLocalDate(), LocalTime.MIN);<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="获取两个日期之间的所有月份"><a href="#获取两个日期之间的所有月份" class="headerlink" title="获取两个日期之间的所有月份"></a>获取两个日期之间的所有月份</h2><ul><li>旧版</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;String&gt; <span class="hljs-title function_">getMonthBetweenByCalendar</span><span class="hljs-params">(String minDate, String maxDate)</span> <span class="hljs-keyword">throws</span> ParseException &#123;<br>    ArrayList&lt;String&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>    <span class="hljs-type">SimpleDateFormat</span> <span class="hljs-variable">sdf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleDateFormat</span>(<span class="hljs-string">&quot;yyyy-MM&quot;</span>);<br>    <span class="hljs-type">Calendar</span> <span class="hljs-variable">min</span> <span class="hljs-operator">=</span> Calendar.getInstance();<br>    <span class="hljs-type">Calendar</span> <span class="hljs-variable">max</span> <span class="hljs-operator">=</span> Calendar.getInstance();<br>    min.setTime(sdf.parse(minDate));<br>    max.setTime(sdf.parse(maxDate));<br>    <span class="hljs-keyword">while</span> (min.before(max) || min.get(Calendar.MONTH) == max.get(Calendar.MONTH)) &#123;<br>        result.add(sdf.format(min.getTime()));<br>        min.add(Calendar.MONTH, <span class="hljs-number">1</span>);<br>    &#125;<br>    <span class="hljs-keyword">return</span> result;<br>&#125;<br></code></pre></td></tr></table></figure><ul><li>Java 8</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;String&gt; <span class="hljs-title function_">getMonthBetweenByLocalDate</span><span class="hljs-params">(String minDate, String maxDate)</span> &#123;<br>    List&lt;String&gt; localDateList = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>    <span class="hljs-type">DateTimeFormatter</span> <span class="hljs-variable">dateTimeFormatter</span> <span class="hljs-operator">=</span> DateTimeFormatter.ofPattern(<span class="hljs-string">&quot;yyyy-MM&quot;</span>);<br>    <span class="hljs-type">LocalDate</span> <span class="hljs-variable">min</span> <span class="hljs-operator">=</span> LocalDate.parse(minDate);<br>    <span class="hljs-type">LocalDate</span> <span class="hljs-variable">max</span> <span class="hljs-operator">=</span> LocalDate.parse(maxDate);<br>    <span class="hljs-keyword">while</span> (min.isBefore(max) || min.getMonth() == max.getMonth()) &#123;<br>        localDateList.add(min.format(dateTimeFormatter));<br>        min = min.plusMonths(<span class="hljs-number">1</span>);<br>    &#125;<br>    <span class="hljs-keyword">return</span> localDateList;<br>&#125;<br></code></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;p&gt;Java 提供了两套日期和时间的接口。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;旧版：&lt;code&gt;Date&lt;/code&gt;、&lt;code&gt;Calenda</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>Layui 表格多选、合并单元格、父子页传值</title>
    <link href="http://www.loquy.cn/posts/daa035a1.html"/>
    <id>http://www.loquy.cn/posts/daa035a1.html</id>
    <published>2022-11-18T09:43:00.000Z</published>
    <updated>2022-11-18T09:43:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>Layui 表格多选、合并单元格、父子页传值的页面效果如下：</p><iframe  height=500width=100%src="/html/layui-demo-2.html"  frameborder=0  allowfullscreen></iframe><h1 id="表格多选"><a href="#表格多选" class="headerlink" title="表格多选"></a>表格多选</h1><p>使用 templet 自定义列模板，实现表格中添加下拉多选。</p><ul><li>方式一：模板中用原生 select 标签进行渲染，以及用 Laytpl 模板引擎处理逻辑进行回显数据。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">initTable</span>(<span class="hljs-params"></span>) &#123;<br>    layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;table&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>        selectHtml = <span class="hljs-string">&#x27;&lt;select name=&quot;sign&quot; lay-filter=&quot;sign&quot; sign=&quot;&#123;&#123;d.sign&#125;&#125;&quot;&quot;&gt;&#x27;</span> +<br>            <span class="hljs-string">&#x27;&lt;option selected=&quot;selected&quot; disabled=&quot;disabled&quot;  style=&quot;display: none&quot; value=&quot;&quot;&gt;&lt;/option&gt;&#x27;</span>;<br>        selectData.<span class="hljs-title function_">forEach</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">item, index</span>) &#123;<br>            <span class="hljs-comment">// 回显数据</span><br>            selectHtml += <span class="hljs-string">&#x27;&#123;&#123;# if(d.sign==\&#x27;&#x27;</span> + item.<span class="hljs-property">name</span> + <span class="hljs-string">&#x27;\&#x27;)&#123;&#125;&#125;&#x27;</span>;<br>            selectHtml += <span class="hljs-string">&#x27;&lt;option value=&quot;&#x27;</span> + item.<span class="hljs-property">value</span> + <span class="hljs-string">&#x27;&quot; selected&gt;&#x27;</span> + item.<span class="hljs-property">name</span> + <span class="hljs-string">&#x27;&lt;/option&gt;&#x27;</span>;<br>            selectHtml += <span class="hljs-string">&#x27;&#123;&#123;#  &#125; else &#123; &#125;&#125;&#x27;</span>;<br>            selectHtml += <span class="hljs-string">&#x27;&lt;option value=&quot;&#x27;</span> + item.<span class="hljs-property">value</span> + <span class="hljs-string">&#x27;&quot;&gt;&#x27;</span> + item.<span class="hljs-property">name</span> + <span class="hljs-string">&#x27;&lt;/option&gt;&#x27;</span>;<br>            selectHtml += <span class="hljs-string">&#x27;&#123;&#123;#  &#125; &#125;&#125;&#x27;</span>;<br>        &#125;)<br>        selectHtml += <span class="hljs-string">&#x27;&lt;/select&gt;&#x27;</span>;<br><br>        layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">render</span>(&#123;<br>            <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#demo&#x27;</span>,<br>            <span class="hljs-attr">page</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//开启分页</span><br>            <span class="hljs-attr">cols</span>: [<br>                [ <span class="hljs-comment">//表头</span><br>                    &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;id&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;ID&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                    &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;username&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;用户名&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                    &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sex&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;性别&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                    &#123;<br>                        <span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sign&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;爱好&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">150</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">templet</span>: <span class="hljs-title function_">stringToHTML</span>(selectHtml)<br>                    &#125;,<br>                    &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;classify&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;职业&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                    &#123; <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;操作&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">100</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">toolbar</span>: <span class="hljs-string">&#x27;#barDemo&#x27;</span>&#125;<br>                ]<br>            ],<br>            <span class="hljs-attr">data</span>: init ? initData : tableData,<br>            <span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">res</span>) &#123;<br>                <span class="hljs-comment">//修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中...</span><br>                <span class="hljs-keyword">var</span> cells = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">&#x27;div[lay-id=&quot;demo&quot;] .layui-table-cell&#x27;</span>);<br>                <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; cells.<span class="hljs-property">length</span>; i++) &#123;<br>                    cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">overflow</span> = <span class="hljs-string">&#x27;unset&#x27;</span>;<br>                    cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">height</span> = <span class="hljs-string">&#x27;auto&#x27;</span>;<br>                &#125;<br>                <span class="hljs-comment">//合并单元格</span><br>                <span class="hljs-title function_">merge</span>(res);<br>            &#125;<br>        &#125;);<br><br>    &#125;);<br>&#125;<br><br></code></pre></td></tr></table></figure><ul><li>方式二：模板中用 xmSelect.js 下拉组件进行渲染。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">initTable</span>(<span class="hljs-params"></span>) &#123;<br>    layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;table&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>        layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">render</span>(&#123;<br>            <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#demo&#x27;</span>,<br>            <span class="hljs-attr">page</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//开启分页</span><br>            <span class="hljs-attr">cols</span>: cols,<br>            <span class="hljs-attr">data</span>: init ? initData : tableData,<br>            <span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">res</span>) &#123;<br>                <span class="hljs-comment">//修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中...</span><br>                <span class="hljs-keyword">var</span> cells = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">&#x27;div[lay-id=&quot;demo&quot;] .layui-table-cell&#x27;</span>);<br>                <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; cells.<span class="hljs-property">length</span>; i++) &#123;<br>                    cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">overflow</span> = <span class="hljs-string">&#x27;unset&#x27;</span>;<br>                    cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">height</span> = <span class="hljs-string">&#x27;auto&#x27;</span>;<br>                &#125;<br>                <span class="hljs-comment">//渲染多选</span><br>                res.<span class="hljs-property">data</span>.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> &#123;<br>                    <span class="hljs-keyword">var</span> xm = xmSelect.<span class="hljs-title function_">render</span>(&#123;<br>                        <span class="hljs-attr">el</span>: <span class="hljs-string">&#x27;#XM-&#x27;</span> + item.<span class="hljs-property">id</span>,<br>                        <span class="hljs-attr">autoRow</span>: <span class="hljs-literal">true</span>,<br>                        <span class="hljs-attr">model</span>: &#123;<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;fixed&#x27;</span>&#125;,<br>                        <span class="hljs-attr">data</span>: [<br>                            &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">1</span>&#125;,<br>                            &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;李四&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">2</span>&#125;,<br>                            &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">3</span>&#125;,<br>                        ]<br>                    &#125;)<br><br>                    item.<span class="hljs-property">__xm</span> = xm;<br>                &#125;)<br>            &#125;<br>        &#125;);<br><br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="合并单元格"><a href="#合并单元格" class="headerlink" title="合并单元格"></a>合并单元格</h1><ul><li>具体思路就是, 通过循环判断每一行的每一列的返回值与上一行的相同列是否相同, </li><li>如果相同就进行行合并 rowspan: mark, 然后把当前行的当前列进行隐藏, </li><li>如果不相同就就记下当前行的行号, 并把标记 mark 重置为1。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 合并单元格</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">merge</span>(<span class="hljs-params">res</span>) &#123;<br>    <span class="hljs-keyword">var</span> data = res.<span class="hljs-property">data</span>;<br>    <span class="hljs-keyword">var</span> mergeIndex = <span class="hljs-number">0</span>;<span class="hljs-comment">//定位需要添加合并属性的行数</span><br>    <span class="hljs-keyword">var</span> mark = <span class="hljs-number">1</span>; <span class="hljs-comment">//这里涉及到简单的运算，mark是计算每次需要合并的格子数</span><br>    <span class="hljs-keyword">var</span> columsName = [<span class="hljs-string">&#x27;sex&#x27;</span>, <span class="hljs-string">&#x27;classify&#x27;</span>];<span class="hljs-comment">// 需要合并的列名称</span><br>    <span class="hljs-keyword">var</span> columsIndex = [<span class="hljs-number">2</span>, <span class="hljs-number">4</span>];<span class="hljs-comment">//需要合并的列索引值</span><br>    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> k = <span class="hljs-number">0</span>; k &lt; columsName.<span class="hljs-property">length</span>; k++) &#123; <span class="hljs-comment">//这里循环所有要合并的列</span><br>        <span class="hljs-keyword">var</span> trArr = $(<span class="hljs-string">&quot;.layui-table-body&gt;.layui-table&quot;</span>).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;tr&quot;</span>);<span class="hljs-comment">//所有行</span><br>        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">1</span>; i &lt; res.<span class="hljs-property">data</span>.<span class="hljs-property">length</span>; i++) &#123; <span class="hljs-comment">//这里循环表格当前的数据</span><br>            <span class="hljs-keyword">var</span> tdCurArr = trArr.<span class="hljs-title function_">eq</span>(i).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;td&quot;</span>).<span class="hljs-title function_">eq</span>(columsIndex[k]);<span class="hljs-comment">//获取当前行的当前列</span><br>            <span class="hljs-keyword">var</span> tdPreArr = trArr.<span class="hljs-title function_">eq</span>(mergeIndex).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;td&quot;</span>).<span class="hljs-title function_">eq</span>(columsIndex[k]);<span class="hljs-comment">//获取相同列的第一列</span><br>            <span class="hljs-keyword">if</span> (data[i][columsName[k]] === data[i - <span class="hljs-number">1</span>][columsName[k]]) &#123; <span class="hljs-comment">//后一行的值与前一行的值做比较，相同就需要合并</span><br>                mark += <span class="hljs-number">1</span>;<br>                tdPreArr.<span class="hljs-title function_">each</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<span class="hljs-comment">//相同列的第一列增加rowspan属性</span><br>                    $(<span class="hljs-variable language_">this</span>).<span class="hljs-title function_">attr</span>(<span class="hljs-string">&quot;rowspan&quot;</span>, mark);<br>                &#125;);<br>                tdCurArr.<span class="hljs-title function_">each</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<span class="hljs-comment">//当前行隐藏</span><br>                    $(<span class="hljs-variable language_">this</span>).<span class="hljs-title function_">css</span>(<span class="hljs-string">&quot;display&quot;</span>, <span class="hljs-string">&quot;none&quot;</span>);<br>                &#125;);<br>            &#125; <span class="hljs-keyword">else</span> &#123;<br>                mergeIndex = i;<br>                mark = <span class="hljs-number">1</span>;<span class="hljs-comment">//一旦前后两行的值不一样了，那么需要合并的格子数mark就需要重新计算</span><br>            &#125;<br>        &#125;<br>        mergeIndex = <span class="hljs-number">0</span>;<br>        mark = <span class="hljs-number">1</span>;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="父子页传值"><a href="#父子页传值" class="headerlink" title="父子页传值"></a>父子页传值</h1><ul><li>获取子页面的 window 对象，从而对子页面进行赋值变量和调用方法。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">//触发单元格工具事件</span><br>layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;tool(demo)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">obj</span>) &#123;<br>    <span class="hljs-keyword">if</span> (obj.<span class="hljs-property">event</span> === <span class="hljs-string">&#x27;open&#x27;</span>) &#123;<br>        layer.<span class="hljs-title function_">open</span>(&#123;<br>            <span class="hljs-attr">type</span>: <span class="hljs-number">2</span>,<br>            <span class="hljs-attr">area</span>: [<span class="hljs-string">&#x27;80%&#x27;</span>, <span class="hljs-string">&#x27;80%&#x27;</span>],<br>            <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;layui-demo-1.html&#x27;</span>,<br>            <span class="hljs-attr">btn</span>: [<span class="hljs-string">&#x27;更换子数据&#x27;</span>, <span class="hljs-string">&#x27;重置子数据&#x27;</span>],<br>            <span class="hljs-attr">btnAlign</span>: <span class="hljs-string">&#x27;c&#x27;</span>,<br>            <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">layero, index</span>) &#123;<br>                <span class="hljs-keyword">var</span> w = $(layero).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;iframe&quot;</span>)[<span class="hljs-number">0</span>].<span class="hljs-property">contentWindow</span>;<br>                w.<span class="hljs-property">cols</span>[<span class="hljs-number">0</span>].<span class="hljs-title function_">push</span>(&#123;<span class="hljs-attr">fixed</span>: <span class="hljs-string">&#x27;right&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;操作&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">180</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">toolbar</span>: <span class="hljs-string">&#x27;#barDemo&#x27;</span>&#125;);<br>                w.<span class="hljs-property">init</span> = <span class="hljs-literal">false</span>;<br>                w.<span class="hljs-title function_">initTable</span>();<br>            &#125;,<br>            <span class="hljs-attr">yes</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">index, layero</span>) &#123;<br>                <span class="hljs-keyword">var</span> w = $(layero).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;iframe&quot;</span>)[<span class="hljs-number">0</span>].<span class="hljs-property">contentWindow</span>;<br>                w.<span class="hljs-property">init</span> = <span class="hljs-literal">false</span>;<br>                w.<span class="hljs-property">tableData</span> = [<br>                    &#123;<br>                        <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10000</span>,<br>                        <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-0&quot;</span>,<br>                        <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>                        <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-0&quot;</span>,<br>                        <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">255</span>,<br>                        <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>                    &#125;<br>                ];<br>                w.<span class="hljs-title function_">initTable</span>();<br>            &#125;, <span class="hljs-attr">btn2</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">index, layero</span>) &#123;<br>                <span class="hljs-keyword">var</span> w = $(layero).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;iframe&quot;</span>)[<span class="hljs-number">0</span>].<span class="hljs-property">contentWindow</span>;<br>                w.<span class="hljs-property">init</span> = <span class="hljs-literal">true</span>;<br>                w.<span class="hljs-title function_">initTable</span>();<br>                <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>            &#125;<br>        &#125;);<br>    &#125;<br>&#125;);<br><br></code></pre></td></tr></table></figure><ul><li>在子页面获取 parent 父级对象，从而对父页面进行赋值变量和调用方法。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">//触发单元格工具事件</span><br>layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;tool(demo)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">obj</span>) &#123;<br>    <span class="hljs-keyword">if</span> (obj.<span class="hljs-property">event</span> === <span class="hljs-string">&#x27;edit&#x27;</span>) &#123;<br>        parent.<span class="hljs-property">tableData</span> = [<br>            &#123;<br>                <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10000</span>,<br>                <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-0&quot;</span>,<br>                <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>                <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-0&quot;</span>,<br>                <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">255</span>,<br>                <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>            &#125;<br>        ];<br>        parent.<span class="hljs-property">init</span> = <span class="hljs-literal">false</span>;<br>        parent.<span class="hljs-title function_">initTable</span>();<br>    &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (obj.<span class="hljs-property">event</span> === <span class="hljs-string">&#x27;reset&#x27;</span>) &#123;<br>        parent.<span class="hljs-property">init</span> = <span class="hljs-literal">true</span>;<br>        parent.<span class="hljs-title function_">initTable</span>();<br>    &#125;<br>&#125;)<br></code></pre></td></tr></table></figure><h1 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h1><details>  <summary>点击查看父页面代码</summary><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>demo<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 引入 layui.css --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;../js/layui-v2.7.6/layui/css/layui.css&quot;</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;demo&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;demo&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-comment">&lt;!-- 引入 layui.js --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../js/layui-v2.7.6/layui/layui.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../js/jquery-3.6.1.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;barDemo&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text/html&quot;</span>&gt;</span><span class="language-handlebars"><span class="language-xml"></span></span><br><span class="language-xml"><span class="language-handlebars">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-btn layui-btn-xs&quot;</span> <span class="hljs-attr">lay-event</span>=<span class="hljs-string">&quot;open&quot;</span>&gt;</span>打开子页面<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span></span><br><span class="language-xml"><span class="language-handlebars"></span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><br></code></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;script&gt;<br>    <span class="hljs-keyword">var</span> selectHtml = <span class="hljs-string">&#x27;&#x27;</span>;<br>    <span class="hljs-keyword">var</span> stringToHTML = <span class="hljs-keyword">function</span> (<span class="hljs-params">str</span>) &#123;<br>        <span class="hljs-keyword">var</span> dom = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">&#x27;div&#x27;</span>);<br>        dom.<span class="hljs-property">innerHTML</span> = str;<br>        <span class="hljs-keyword">return</span> dom;<br>    &#125;<br>    <span class="hljs-keyword">var</span> init = <span class="hljs-literal">false</span>;<br>    <span class="hljs-keyword">var</span> initData = [<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10000</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-0&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">255</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10001</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-1&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;李四&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">884</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;词人&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10002</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-2&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;王五&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">650</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;酱油&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10003</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-3&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">362</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;诗人&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10004</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-4&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">807</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10005</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-5&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">173</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10006</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-6&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">982</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10007</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-7&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">727</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10008</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-8&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">951</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;词人&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10009</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-9&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;张三&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">484</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;词人&quot;</span>,<br>        &#125;<br>    ];<br>    <span class="hljs-keyword">var</span> tableData = initData;<br>    <span class="hljs-keyword">var</span> selectData = [<br>        &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">1</span>&#125;,<br>        &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;李四&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">2</span>&#125;,<br>        &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">3</span>&#125;,<br>    ]<br><br>    <span class="hljs-title function_">initTable</span>();<br><br>    <span class="hljs-keyword">function</span> <span class="hljs-title function_">initTable</span>(<span class="hljs-params"></span>) &#123;<br>        layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;table&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>            selectHtml = <span class="hljs-string">&#x27;&lt;select name=&quot;sign&quot; lay-filter=&quot;sign&quot; sign=&quot;&#123;&#123;d.sign&#125;&#125;&quot;&quot;&gt;&#x27;</span> +<br>                <span class="hljs-string">&#x27;&lt;option selected=&quot;selected&quot; disabled=&quot;disabled&quot;  style=&quot;display: none&quot; value=&quot;&quot;&gt;&lt;/option&gt;&#x27;</span>;<br>            selectData.<span class="hljs-title function_">forEach</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">item, index</span>) &#123;<br>                <span class="hljs-comment">// 回显数据</span><br>                selectHtml += <span class="hljs-string">&#x27;&#123;&#123;# if(d.sign==\&#x27;&#x27;</span> + item.<span class="hljs-property">name</span> + <span class="hljs-string">&#x27;\&#x27;)&#123;&#125;&#125;&#x27;</span>;<br>                selectHtml += <span class="hljs-string">&#x27;&lt;option value=&quot;&#x27;</span> + item.<span class="hljs-property">value</span> + <span class="hljs-string">&#x27;&quot; selected&gt;&#x27;</span> + item.<span class="hljs-property">name</span> + <span class="hljs-string">&#x27;&lt;/option&gt;&#x27;</span>;<br>                selectHtml += <span class="hljs-string">&#x27;&#123;&#123;#  &#125; else &#123; &#125;&#125;&#x27;</span>;<br>                selectHtml += <span class="hljs-string">&#x27;&lt;option value=&quot;&#x27;</span> + item.<span class="hljs-property">value</span> + <span class="hljs-string">&#x27;&quot;&gt;&#x27;</span> + item.<span class="hljs-property">name</span> + <span class="hljs-string">&#x27;&lt;/option&gt;&#x27;</span>;<br>                selectHtml += <span class="hljs-string">&#x27;&#123;&#123;#  &#125; &#125;&#125;&#x27;</span>;<br>            &#125;)<br>            selectHtml += <span class="hljs-string">&#x27;&lt;/select&gt;&#x27;</span>;<br><br>            layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">render</span>(&#123;<br>                <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#demo&#x27;</span>,<br>                <span class="hljs-attr">page</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//开启分页</span><br>                <span class="hljs-attr">cols</span>: [<br>                    [ <span class="hljs-comment">//表头</span><br>                        &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;id&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;ID&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                        &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;username&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;用户名&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                        &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sex&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;性别&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                        &#123;<br>                            <span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sign&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;爱好&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">150</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">templet</span>: <span class="hljs-title function_">stringToHTML</span>(selectHtml)<br>                        &#125;,<br>                        &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;classify&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;职业&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>                        &#123; <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;操作&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">100</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">toolbar</span>: <span class="hljs-string">&#x27;#barDemo&#x27;</span>&#125;<br>                    ]<br>                ],<br>                <span class="hljs-attr">data</span>: init ? initData : tableData,<br>                <span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">res</span>) &#123;<br>                    <span class="hljs-comment">//修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中...</span><br>                    <span class="hljs-keyword">var</span> cells = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">&#x27;div[lay-id=&quot;demo&quot;] .layui-table-cell&#x27;</span>);<br>                    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; cells.<span class="hljs-property">length</span>; i++) &#123;<br>                        cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">overflow</span> = <span class="hljs-string">&#x27;unset&#x27;</span>;<br>                        cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">height</span> = <span class="hljs-string">&#x27;auto&#x27;</span>;<br>                    &#125;<br>                    <span class="hljs-comment">//合并单元格</span><br>                    <span class="hljs-title function_">merge</span>(res);<br>                &#125;<br>            &#125;);<br><br>        &#125;);<br>    &#125;<br><br>    layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;form&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>        <span class="hljs-comment">// 监听下拉框编辑</span><br>        layui.<span class="hljs-property">form</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(sign)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) &#123;<br>            <span class="hljs-keyword">var</span> sign = data.<span class="hljs-property">elem</span>.<span class="hljs-title function_">getAttribute</span>(<span class="hljs-string">&quot;sign&quot;</span>);<br>            layui.<span class="hljs-property">layer</span>.<span class="hljs-title function_">alert</span>(sign + <span class="hljs-string">&#x27;：&#x27;</span> + data.<span class="hljs-property">value</span>)<br>        &#125;)<br>    &#125;);<br><br>    <span class="hljs-comment">//触发单元格工具事件</span><br>    layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;tool(demo)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">obj</span>) &#123;<br>        <span class="hljs-keyword">if</span> (obj.<span class="hljs-property">event</span> === <span class="hljs-string">&#x27;open&#x27;</span>) &#123;<br>            layer.<span class="hljs-title function_">open</span>(&#123;<br>                <span class="hljs-attr">type</span>: <span class="hljs-number">2</span>,<br>                <span class="hljs-attr">area</span>: [<span class="hljs-string">&#x27;80%&#x27;</span>, <span class="hljs-string">&#x27;80%&#x27;</span>],<br>                <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;layui-demo-1.html&#x27;</span>,<br>                <span class="hljs-attr">btn</span>: [<span class="hljs-string">&#x27;更换子数据&#x27;</span>, <span class="hljs-string">&#x27;重置子数据&#x27;</span>],<br>                <span class="hljs-attr">btnAlign</span>: <span class="hljs-string">&#x27;c&#x27;</span>,<br>                <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">layero, index</span>) &#123;<br>                    <span class="hljs-keyword">var</span> w = $(layero).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;iframe&quot;</span>)[<span class="hljs-number">0</span>].<span class="hljs-property">contentWindow</span>;<br>                    w.<span class="hljs-property">cols</span>[<span class="hljs-number">0</span>].<span class="hljs-title function_">push</span>(&#123;<span class="hljs-attr">fixed</span>: <span class="hljs-string">&#x27;right&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;操作&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">180</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">toolbar</span>: <span class="hljs-string">&#x27;#barDemo&#x27;</span>&#125;);<br>                    w.<span class="hljs-property">init</span> = <span class="hljs-literal">false</span>;<br>                    w.<span class="hljs-title function_">initTable</span>();<br>                &#125;,<br>                <span class="hljs-attr">yes</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">index, layero</span>) &#123;<br>                    <span class="hljs-keyword">var</span> w = $(layero).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;iframe&quot;</span>)[<span class="hljs-number">0</span>].<span class="hljs-property">contentWindow</span>;<br>                    w.<span class="hljs-property">init</span> = <span class="hljs-literal">false</span>;<br>                    w.<span class="hljs-property">tableData</span> = [<br>                        &#123;<br>                            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10000</span>,<br>                            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-0&quot;</span>,<br>                            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>                            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-0&quot;</span>,<br>                            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">255</span>,<br>                            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>                        &#125;<br>                    ];<br>                    w.<span class="hljs-title function_">initTable</span>();<br>                &#125;, <span class="hljs-attr">btn2</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">index, layero</span>) &#123;<br>                    <span class="hljs-keyword">var</span> w = $(layero).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;iframe&quot;</span>)[<span class="hljs-number">0</span>].<span class="hljs-property">contentWindow</span>;<br>                    w.<span class="hljs-property">init</span> = <span class="hljs-literal">true</span>;<br>                    w.<span class="hljs-title function_">initTable</span>();<br>                    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>                &#125;<br>            &#125;);<br>        &#125;<br>    &#125;);<br>    <span class="hljs-comment">// 合并单元格</span><br>    <span class="hljs-keyword">function</span> <span class="hljs-title function_">merge</span>(<span class="hljs-params">res</span>) &#123;<br>        <span class="hljs-keyword">var</span> data = res.<span class="hljs-property">data</span>;<br>        <span class="hljs-keyword">var</span> mergeIndex = <span class="hljs-number">0</span>;<span class="hljs-comment">//定位需要添加合并属性的行数</span><br>        <span class="hljs-keyword">var</span> mark = <span class="hljs-number">1</span>; <span class="hljs-comment">//这里涉及到简单的运算，mark是计算每次需要合并的格子数</span><br>        <span class="hljs-keyword">var</span> columsName = [<span class="hljs-string">&#x27;sex&#x27;</span>, <span class="hljs-string">&#x27;classify&#x27;</span>];<span class="hljs-comment">// 需要合并的列名称</span><br>        <span class="hljs-keyword">var</span> columsIndex = [<span class="hljs-number">2</span>, <span class="hljs-number">4</span>];<span class="hljs-comment">//需要合并的列索引值</span><br>        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> k = <span class="hljs-number">0</span>; k &lt; columsName.<span class="hljs-property">length</span>; k++) &#123; <span class="hljs-comment">//这里循环所有要合并的列</span><br>            <span class="hljs-keyword">var</span> trArr = $(<span class="hljs-string">&quot;.layui-table-body&gt;.layui-table&quot;</span>).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;tr&quot;</span>);<span class="hljs-comment">//所有行</span><br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">1</span>; i &lt; res.<span class="hljs-property">data</span>.<span class="hljs-property">length</span>; i++) &#123; <span class="hljs-comment">//这里循环表格当前的数据</span><br>                <span class="hljs-keyword">var</span> tdCurArr = trArr.<span class="hljs-title function_">eq</span>(i).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;td&quot;</span>).<span class="hljs-title function_">eq</span>(columsIndex[k]);<span class="hljs-comment">//获取当前行的当前列</span><br>                <span class="hljs-keyword">var</span> tdPreArr = trArr.<span class="hljs-title function_">eq</span>(mergeIndex).<span class="hljs-title function_">find</span>(<span class="hljs-string">&quot;td&quot;</span>).<span class="hljs-title function_">eq</span>(columsIndex[k]);<span class="hljs-comment">//获取相同列的第一列</span><br>                <span class="hljs-keyword">if</span> (data[i][columsName[k]] === data[i - <span class="hljs-number">1</span>][columsName[k]]) &#123; <span class="hljs-comment">//后一行的值与前一行的值做比较，相同就需要合并</span><br>                    mark += <span class="hljs-number">1</span>;<br>                    tdPreArr.<span class="hljs-title function_">each</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<span class="hljs-comment">//相同列的第一列增加rowspan属性</span><br>                        $(<span class="hljs-variable language_">this</span>).<span class="hljs-title function_">attr</span>(<span class="hljs-string">&quot;rowspan&quot;</span>, mark);<br>                    &#125;);<br>                    tdCurArr.<span class="hljs-title function_">each</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<span class="hljs-comment">//当前行隐藏</span><br>                        $(<span class="hljs-variable language_">this</span>).<span class="hljs-title function_">css</span>(<span class="hljs-string">&quot;display&quot;</span>, <span class="hljs-string">&quot;none&quot;</span>);<br>                    &#125;);<br>                &#125; <span class="hljs-keyword">else</span> &#123;<br>                    mergeIndex = i;<br>                    mark = <span class="hljs-number">1</span>;<span class="hljs-comment">//一旦前后两行的值不一样了，那么需要合并的格子数mark就需要重新计算</span><br>                &#125;<br>            &#125;<br>            mergeIndex = <span class="hljs-number">0</span>;<br>            mark = <span class="hljs-number">1</span>;<br>        &#125;<br>    &#125;<br>&lt;/script&gt;<br></code></pre></td></tr></table></figure></details><details>  <summary>点击查看子页面页面代码</summary><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>demo<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 引入 layui.css --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;../js/layui-v2.7.6/layui/css/layui.css&quot;</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;demo&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;demo&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-comment">&lt;!-- 引入 layui.js --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../js/layui-v2.7.6/layui/layui.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../js/xm-select-v1.2.4/dist/xm-select.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../js/jquery-3.6.1.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;barDemo&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text/html&quot;</span>&gt;</span><span class="language-handlebars"><span class="language-xml"></span></span><br><span class="language-xml"><span class="language-handlebars">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-btn layui-btn-xs&quot;</span> <span class="hljs-attr">lay-event</span>=<span class="hljs-string">&quot;edit&quot;</span>&gt;</span>更换父数据<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span></span><br><span class="language-xml"><span class="language-handlebars">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-btn layui-btn-danger layui-btn-xs&quot;</span> <span class="hljs-attr">lay-event</span>=<span class="hljs-string">&quot;reset&quot;</span>&gt;</span>重置父数据<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span></span><br><span class="language-xml"><span class="language-handlebars"></span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><br></code></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;script&gt;<br>    <span class="hljs-keyword">var</span> init = <span class="hljs-literal">false</span>;<br>    <span class="hljs-keyword">var</span> initData = [<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10000</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-0&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-0&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">255</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10001</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-1&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-1&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">884</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;词人&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10002</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-2&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-2&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">650</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;酱油&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10003</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-3&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-3&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">362</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;诗人&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10004</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-4&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-4&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">807</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10005</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-5&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-5&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">173</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10006</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-6&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-6&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">982</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10007</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-7&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-7&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">727</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10008</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-8&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;男&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-8&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">951</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;词人&quot;</span>,<br>        &#125;,<br>        &#123;<br>            <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10009</span>,<br>            <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-9&quot;</span>,<br>            <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>            <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-9&quot;</span>,<br>            <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">484</span>,<br>            <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;词人&quot;</span>,<br>        &#125;<br>    ];<br>    <span class="hljs-keyword">var</span> tableData = initData;<br>    <span class="hljs-keyword">var</span> cols = [<br>        [ <span class="hljs-comment">//表头</span><br>            &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;id&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;ID&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>            &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;username&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;用户名&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>            &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sex&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;性别&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>            &#123;<br>                <span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sign&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;爱好&#x27;</span>, <span class="hljs-attr">minWidth</span>: <span class="hljs-number">150</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>, <span class="hljs-attr">templet</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">d</span>) &#123;<br>                    <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;&lt;div id=&quot;XM-&#x27;</span> + d.<span class="hljs-property">id</span> + <span class="hljs-string">&#x27;&quot; &gt;&lt;/div&gt;&#x27;</span><br>                &#125;<br>            &#125;,<br>            &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;classify&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;职业&#x27;</span>, <span class="hljs-attr">align</span>: <span class="hljs-string">&quot;center&quot;</span>&#125;,<br>        ]<br>    ];<br><br>    <span class="hljs-title function_">initTable</span>();<br><br>    <span class="hljs-keyword">function</span> <span class="hljs-title function_">initTable</span>(<span class="hljs-params"></span>) &#123;<br>        layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;table&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>            layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">render</span>(&#123;<br>                <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#demo&#x27;</span>,<br>                <span class="hljs-attr">page</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//开启分页</span><br>                <span class="hljs-attr">cols</span>: cols,<br>                <span class="hljs-attr">data</span>: init ? initData : tableData,<br>                <span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">res</span>) &#123;<br>                    <span class="hljs-comment">//修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中...</span><br>                    <span class="hljs-keyword">var</span> cells = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">&#x27;div[lay-id=&quot;demo&quot;] .layui-table-cell&#x27;</span>);<br>                    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; cells.<span class="hljs-property">length</span>; i++) &#123;<br>                        cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">overflow</span> = <span class="hljs-string">&#x27;unset&#x27;</span>;<br>                        cells[i].<span class="hljs-property">style</span>.<span class="hljs-property">height</span> = <span class="hljs-string">&#x27;auto&#x27;</span>;<br>                    &#125;<br>                    <span class="hljs-comment">//渲染多选</span><br>                    res.<span class="hljs-property">data</span>.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> &#123;<br>                        <span class="hljs-keyword">var</span> xm = xmSelect.<span class="hljs-title function_">render</span>(&#123;<br>                            <span class="hljs-attr">el</span>: <span class="hljs-string">&#x27;#XM-&#x27;</span> + item.<span class="hljs-property">id</span>,<br>                            <span class="hljs-attr">autoRow</span>: <span class="hljs-literal">true</span>,<br>                            <span class="hljs-attr">model</span>: &#123;<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;fixed&#x27;</span>&#125;,<br>                            <span class="hljs-attr">data</span>: [<br>                                &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">1</span>&#125;,<br>                                &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;李四&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">2</span>&#125;,<br>                                &#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">3</span>&#125;,<br>                            ]<br>                        &#125;)<br><br>                        item.<span class="hljs-property">__xm</span> = xm;<br>                    &#125;)<br>                &#125;<br>            &#125;);<br><br>        &#125;);<br>    &#125;<br><br>    <span class="hljs-comment">//触发单元格工具事件</span><br>    layui.<span class="hljs-property">table</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;tool(demo)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">obj</span>) &#123;<br>        <span class="hljs-keyword">if</span> (obj.<span class="hljs-property">event</span> === <span class="hljs-string">&#x27;edit&#x27;</span>) &#123;<br>            parent.<span class="hljs-property">tableData</span> = [<br>                &#123;<br>                    <span class="hljs-string">&quot;id&quot;</span>: <span class="hljs-number">10000</span>,<br>                    <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;user-0&quot;</span>,<br>                    <span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span>,<br>                    <span class="hljs-string">&quot;sign&quot;</span>: <span class="hljs-string">&quot;签名-0&quot;</span>,<br>                    <span class="hljs-string">&quot;experience&quot;</span>: <span class="hljs-number">255</span>,<br>                    <span class="hljs-string">&quot;classify&quot;</span>: <span class="hljs-string">&quot;作家&quot;</span>,<br>                &#125;<br>            ];<br>            parent.<span class="hljs-property">init</span> = <span class="hljs-literal">false</span>;<br>            parent.<span class="hljs-title function_">initTable</span>();<br>        &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (obj.<span class="hljs-property">event</span> === <span class="hljs-string">&#x27;reset&#x27;</span>) &#123;<br>            parent.<span class="hljs-property">init</span> = <span class="hljs-literal">true</span>;<br>            parent.<span class="hljs-title function_">initTable</span>();<br>        &#125;<br>    &#125;)<br><br>    $(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>        <span class="hljs-comment">//表格滚动时 重新计算位置</span><br>        <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">&#x27;.layui-table-body&#x27;</span>).<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">&#x27;scroll&#x27;</span>, <span class="hljs-function">() =&gt;</span> &#123;<br>            xmSelect.<span class="hljs-title function_">get</span>().<span class="hljs-title function_">forEach</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">item</span>) &#123;<br>                item.<span class="hljs-title function_">calcPosition</span>();<br>            &#125;)<br>        &#125;)<br>    &#125;)<br>&lt;/script&gt;<br></code></pre></td></tr></table></figure></details>]]></content>
    
    
    <summary type="html">Layui 表格自定义多选和合并单元格以及 layer 弹窗父子页相互传值。</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/JavaScript/"/>
    
    
    <category term="JavaScript" scheme="http://www.loquy.cn/tags/JavaScript/"/>
    
    <category term="JQuery" scheme="http://www.loquy.cn/tags/JQuery/"/>
    
    <category term="Layui" scheme="http://www.loquy.cn/tags/Layui/"/>
    
  </entry>
  
  <entry>
    <title>Java 调用 Web Service</title>
    <link href="http://www.loquy.cn/posts/b10633f0.html"/>
    <id>http://www.loquy.cn/posts/b10633f0.html</id>
    <published>2022-10-28T02:16:00.000Z</published>
    <updated>2022-10-28T07:46:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><h2 id="Web-服务"><a href="#Web-服务" class="headerlink" title="Web 服务"></a>Web 服务</h2><p>Web 服务是一种服务导向架构的技术，通过标准的 Web 协议提供服务，目的是保证不同平台的应用服务可以互操作。</p><p>根据 W3C 的定义，Web 服务（Web service）应当是一个软件系统，用以支持网络间不同机器的互动操作。网络服务通常是许多应用程序接口（API）所组成的，它们透过网络，例如国际互联网（Internet）的远程服务器端，执行客户所提交服务的请求。</p><p>尽管 W3C 的定义涵盖诸多相异且无法介分的系统，不过通常我们指有关于主从式架构（Client-Server）之间根据 SOAP 协议进行传递 XML 格式消息。无论定义还是实现，Web 服务过程中会由服务器提供一个机器可读的描述（通常基于 WSDL）以辨识服务器所提供的 WEB 服务。另外，虽然 WSDL 不是 SOAP 服务端点的必要条件，但目前基于 Java 的主流 Web 服务开发框架往往需要 WSDL 实现客户端的源代码生成。一些工业标准化组织，比如 WS-I，就在 Web 服务定义中强制包含 SOAP 和 WSDL。</p><h2 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h2><p>核心定义<br>考虑到并没某个独立文档包含一切相关内容，可采用模块化的方式给出对 Web 服务的描述，但不能给出一个“绝对全面和准确”的定义。受外部环境和实现技术影响，各方给出的核心定义可能稍有出入，但通常包括：</p><p><strong>SOAP</strong><br>一个基于 XML 的可扩展消息信封格式，需同时绑定一个网络传输协议。这个协议通常是 HTTP 或 HTTPS，但也可能是 SMTP 或 XMPP。</p><p><strong>WSDL</strong><br>一个 XML 格式文档，用以描述服务端口访问方式和使用协议的细节。通常用来辅助生成服务器和客户端代码及配置信息。</p><p><strong>UDDI</strong><br>一个用来发布和搜索 WEB 服务的协议，应用程序可借由此协议在设计或运行时找到目标WEB服务。<br>这些标准由这些组织制订：W3C 负责 XML、SOAP 及 WSDL；OASIS 负责 UDDI。</p><h1 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h1><ul><li>先引入 axis 包</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.apache.axis/axis --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.axis<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>axis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br></code></pre></td></tr></table></figure><ul><li>具体代码实现</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.webService;<br><br><span class="hljs-keyword">import</span> org.apache.axis.client.Call;<br><span class="hljs-keyword">import</span> org.apache.axis.client.Service;<br><span class="hljs-keyword">import</span> org.apache.axis.encoding.XMLType;<br><span class="hljs-keyword">import</span> javax.xml.namespace.QName;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CallWebService</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">ENDPOINT</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;http://localhost:3000/test?wsdl&quot;</span>;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">NAMESPACE</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;http://tempuri.org/&quot;</span>;<br>   <br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">getGuid</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">Service</span> <span class="hljs-variable">service</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Service</span>();<br>        <span class="hljs-type">Call</span> <span class="hljs-variable">call</span> <span class="hljs-operator">=</span> (Call) service.createCall();<br>        call.setTargetEndpointAddress(ENDPOINT);<br>        <span class="hljs-comment">// WSDL 里面描述的接口名称(要调用的方法)</span><br>        call.setOperationName(<span class="hljs-keyword">new</span> <span class="hljs-title class_">QName</span>(NAMESPACE, <span class="hljs-string">&quot;login&quot;</span>));<br>        <span class="hljs-comment">// 接口方法的参数名, 参数类型, 参数模式  IN(输入), OUT(输出) or INOUT(输入输出)</span><br>        call.addParameter(<span class="hljs-string">&quot;userId&quot;</span>, XMLType.XSD_STRING, ParameterMode.IN);<br>        call.addParameter(<span class="hljs-string">&quot;password&quot;</span>, XMLType.XSD_STRING, ParameterMode.IN);<br>        <span class="hljs-comment">// 设置被调用方法的返回值类型</span><br>        call.setReturnType(XMLType.XSD_STRING);<br>        <span class="hljs-comment">// 设置超时</span><br>        call.setTimeout(<span class="hljs-number">30</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>);<br>        <span class="hljs-comment">// 设置方法中参数的值</span><br>        Object[] paramValues = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>[] &#123;<span class="hljs-string">&quot;test&quot;</span>, <span class="hljs-string">&quot;test&quot;</span>&#125;;<br>        <span class="hljs-comment">// 给方法传递参数，并且调用方法</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> (String) call.invoke(paramValues);<br><br>        System.out.println(result);<br><br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br>&#125;<br><br><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://zh.wikipedia.org/wiki/Web%E6%9C%8D%E5%8A%A1">维基百科</a></li><li><a href="https://blog.csdn.net/coolcoffee168/article/details/48490263">CSDN</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;h2 id=&quot;Web-服务&quot;&gt;&lt;a href=&quot;#Web-服务&quot; class=&quot;headerlink&quot; title=&quot;Web 服务&quot;&gt;&lt;/a&gt;W</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>Windows 下定时重启 Tomcat</title>
    <link href="http://www.loquy.cn/posts/36df66f4.html"/>
    <id>http://www.loquy.cn/posts/36df66f4.html</id>
    <published>2022-10-09T06:02:00.000Z</published>
    <updated>2022-10-09T06:11:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><pre><code class="hljs">维护很老的项目时，tomcat 隔几天会死掉一次；其中代码肯定有问题的，但是历史遗留的代码必然有很多坑且非原作者很难去改动；无奈出此下策：写个批处理脚本加入任务计划去定时重启 tomcat；脚本原理是根据端口关闭 tomcat 所在的进程，杀死进程后调用 startup.bat 重新启动 tomcat。</code></pre><h1 id="批处理脚本"><a href="#批处理脚本" class="headerlink" title="批处理脚本"></a>批处理脚本</h1><p>1、先查看 tomcat 配置目录 conf 下的 server.xml 文件里的两个端口号</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">Server</span> <span class="hljs-attr">port</span>=<span class="hljs-string">&quot;8005&quot;</span> <span class="hljs-attr">shutdown</span>=<span class="hljs-string">&quot;SHUTDOWN&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 省略 --&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">Service</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;Catalina&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">Connector</span> <span class="hljs-attr">port</span>=<span class="hljs-string">&quot;8080&quot;</span> <span class="hljs-attr">protocol</span>=<span class="hljs-string">&quot;HTTP/1.1&quot;</span></span><br><span class="hljs-tag">               <span class="hljs-attr">connectionTimeout</span>=<span class="hljs-string">&quot;20000&quot;</span></span><br><span class="hljs-tag">               <span class="hljs-attr">redirectPort</span>=<span class="hljs-string">&quot;8443&quot;</span> /&gt;</span><br>     <span class="hljs-comment">&lt;!-- 省略 --&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">Service</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">Server</span>&gt;</span><br></code></pre></td></tr></table></figure><p>2、把端口写入到重启 tomcat 的批处理脚本里</p><figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs bat">@<span class="hljs-built_in">echo</span> off &amp; <span class="hljs-built_in">setlocal</span> EnableDelayedExpansion <br><span class="hljs-built_in">title</span> 定时重启 tomcat<br><br>:: Tomcat 路径和端口<br><span class="hljs-built_in">set</span> tomcat_root_path=H:<br><span class="hljs-built_in">set</span> tomcat_ports=<span class="hljs-number">8005</span>,<span class="hljs-number">8080</span><br><span class="hljs-built_in">set</span> tomcat_path=H:\environment\apache-tomcat-<span class="hljs-number">8</span>.<span class="hljs-number">5</span>.<span class="hljs-number">72</span>\bin<br><br>::循环关闭端口对应的进程<br><span class="hljs-keyword">for</span> <span class="hljs-variable">%%a</span> <span class="hljs-keyword">in</span> (<span class="hljs-variable">%tomcat_ports%</span>) <span class="hljs-keyword">do</span> (<br><span class="hljs-built_in">set</span> pid=<span class="hljs-number">0</span><br><span class="hljs-keyword">for</span> /f &quot;tokens=<span class="hljs-number">2</span>,<span class="hljs-number">5</span>&quot; <span class="hljs-variable">%%b</span> <span class="hljs-keyword">in</span> (&#x27;netstat -ano ^| <span class="hljs-built_in">findstr</span> &quot;:<span class="hljs-variable">%%a</span>&quot;&#x27;) <span class="hljs-keyword">do</span> (<br><span class="hljs-built_in">set</span> temp=<span class="hljs-variable">%%b</span><br><span class="hljs-keyword">for</span> /f &quot;usebackq delims=: tokens=<span class="hljs-number">1</span>,<span class="hljs-number">2</span>&quot; <span class="hljs-variable">%%i</span> <span class="hljs-keyword">in</span> (`<span class="hljs-built_in">set</span> temp`) <span class="hljs-keyword">do</span> (<br><span class="hljs-keyword">if</span> <span class="hljs-variable">%%j</span>==<span class="hljs-variable">%%a</span> (<br><span class="hljs-built_in">taskkill</span> /f /pid <span class="hljs-variable">%%c</span><br><span class="hljs-built_in">set</span> pid=<span class="hljs-variable">%%c</span><br><span class="hljs-built_in">echo</span> 端口号【<span class="hljs-variable">%%a</span>】相关进程已杀死<br>) <span class="hljs-keyword">else</span> (<br><span class="hljs-built_in">echo</span> 不是本机占用端口【<span class="hljs-variable">%%a</span>】<br>)<br>)<br>)<br><span class="hljs-keyword">if</span> <span class="hljs-variable">!pid!</span>==<span class="hljs-number">0</span> (<br><span class="hljs-built_in">echo</span> 端口号【<span class="hljs-variable">%%a</span>】没有占用<br>)<br>) <br><span class="hljs-built_in">echo</span> tomcat 相关进程已杀死 <br>::延迟 <span class="hljs-number">10</span> 秒<br>TIMEOUT /T <span class="hljs-number">10</span><br><br><span class="hljs-built_in">echo</span> 切换到 tomcat 目录，调用 startup.bat <br><span class="hljs-variable">%tomcat_root_path%</span><br><span class="hljs-built_in">cd</span> <span class="hljs-variable">%tomcat_path%</span><br><span class="hljs-keyword">call</span> startup.bat <br><span class="hljs-built_in">echo</span> tomcat 已启动!<br> <br><span class="hljs-built_in">echo</span> 操作完成!<br><span class="hljs-keyword">exit</span><br></code></pre></td></tr></table></figure><h1 id="定时重启"><a href="#定时重启" class="headerlink" title="定时重启"></a>定时重启</h1><p>1、底部任务栏搜索框输入：任务计划程序，然后打开；</p><p>2、创建基本任务，添加任务描述；</p><p>3、触发器，选择定时的时间；</p><p>4、操作，启动程序，选择重启 tomcat 的批处理脚本；</p><p>5、完成。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;维护很老的项目时，tomcat 隔几天会死掉一次；

其中代码肯定有问题的，但是历史遗留的代码必然</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    <category term="Windows" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Windows/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="Tomcat" scheme="http://www.loquy.cn/tags/Tomcat/"/>
    
    <category term="Windows" scheme="http://www.loquy.cn/tags/Windows/"/>
    
  </entry>
  
  <entry>
    <title>Java IO 流</title>
    <link href="http://www.loquy.cn/posts/cda4c274.html"/>
    <id>http://www.loquy.cn/posts/cda4c274.html</id>
    <published>2022-09-27T09:26:00.000Z</published>
    <updated>2022-09-28T00:51:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><h2 id="IO"><a href="#IO" class="headerlink" title="IO"></a>IO</h2><p>通过<a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E6%B5%81?fromModule=lemma_inlink">数据流</a>、<a href="https://baike.baidu.com/item/%E5%BA%8F%E5%88%97%E5%8C%96/2890184?fromModule=lemma_inlink">序列化</a>和文件系统提供系统输入和输出。</p><h2 id="流"><a href="#流" class="headerlink" title="流"></a>流</h2><p>流是一个很形象的概念，当程序需要读取数据的时候，就会开启一个通向<a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E6%BA%90?fromModule=lemma_inlink">数据源</a>的流，这个数据源可以是文件，内存，或是网络连接。类似的，当程序需要写入数据的时候，就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p><a href="https://baike.baidu.com/item/Java/85979?fromModule=lemma_inlink">Java</a> 把这些不同来源和目标的数据都统一抽象为数据流。Java 语言的输入输出功能是十分强大而灵活的，美中不足的是看上去输入输出的代码并不是很简洁，因为你往往需要包装许多不同的对象。</p><p>在 Java 类库中，IO 部分的内容是很庞大的，因为它涉及的领域很广泛:<a href="https://baike.baidu.com/item/%E6%A0%87%E5%87%86%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA?fromModule=lemma_inlink">标准输入输出</a>，文件的操作，网络上的数据流，字符串流，对象流，zip 文件流。</p><h1 id="File-文件类"><a href="#File-文件类" class="headerlink" title="File 文件类"></a>File 文件类</h1><p>在 Java 中，File 类是 java.io 包中唯一代表磁盘文件本身的对象，也就是说，如果希望在程序中操作文件和目录，则都可以通过 File 类来完成。File 类定义了一些方法来操作文件，如新建、删除、重命名文件和目录等。</p><p>File 类不能访问文件内容本身，如果需要访问文件内容本身，则需要使用输入&#x2F;输出流。</p><p>File 类提供了如下三种形式构造方法。</p><ol><li>File(String path)：如果 path 是实际存在的路径，则该 File 对象表示的是目录；如果 path 是文件名，则该 File 对象表示的是文件。</li><li>File(String path, String name)：path 是路径名，name 是文件名。</li><li>File(File dir, String name)：dir 是路径对象，name 是文件名。</li></ol><p>使用任意一个构造方法都可以创建一个 File 对象，然后调用其提供的方法对文件进行操作。在表中列出了 File 类的常用方法及说明。</p><table><thead><tr><th>方法名称</th><th>说明</th></tr></thead><tbody><tr><td>boolean canRead()</td><td>测试应用程序是否能从指定的文件中进行读取</td></tr><tr><td>boolean canWrite()</td><td>测试应用程序是否能写当前文件</td></tr><tr><td>boolean delete()</td><td>删除当前对象指定的文件</td></tr><tr><td>boolean exists()</td><td>测试当前 File 是否存在</td></tr><tr><td>String getAbsolutePath()</td><td>返回由该对象表示的文件的绝对路径名</td></tr><tr><td>String getName()</td><td>返回表示当前对象的文件名或路径名（如果是路径，则返回最后一级子路径名）</td></tr><tr><td>String getParent()</td><td>返回当前 File 对象所对应目录（最后一级子目录）的父目录名</td></tr><tr><td>boolean isAbsolute()</td><td>测试当前 File 对象表示的文件是否为一个绝对路径名。该方法消除了不同平台的差异，可以直接判断 file 对象是否为绝对路径。在 UNIX&#x2F;Linux&#x2F;BSD 等系统上，如果路径名开头是一条斜线<code>/</code>，则表明该 File 对象对应一个绝对路径；在 Windows 等系统上，如果路径开头是盘符，则说明它是一个绝对路径。</td></tr><tr><td>boolean isDirectory()</td><td>测试当前 File 对象表示的文件是否为一个路径</td></tr><tr><td>boolean isFile()</td><td>测试当前 File 对象表示的文件是否为一个“普通”文件</td></tr><tr><td>long lastModified()</td><td>返回当前 File 对象表示的文件最后修改的时间</td></tr><tr><td>long length()</td><td>返回当前 File 对象表示的文件长度</td></tr><tr><td>String[] list()</td><td>返回当前 File 对象指定的路径文件列表</td></tr><tr><td>String[] list(FilenameFilter)</td><td>返回当前 File 对象指定的目录中满足指定过滤器的文件列表</td></tr><tr><td>boolean mkdir()</td><td>创建一个目录，它的路径名由当前 File 对象指定</td></tr><tr><td>boolean mkdirs()</td><td>创建一个目录，它的路径名由当前 File 对象指定</td></tr><tr><td>boolean renameTo(File)</td><td>将当前 File 对象指定的文件更名为给定参数 File 指定的路径名</td></tr></tbody></table><h1 id="IO-流的分类"><a href="#IO-流的分类" class="headerlink" title="IO 流的分类"></a>IO 流的分类</h1><h2 id="流向和数据类型"><a href="#流向和数据类型" class="headerlink" title="流向和数据类型"></a>流向和数据类型</h2><p>根据数据的流向分为：<strong>输入流</strong> 和 <strong>输出流</strong>。</p><ul><li><strong>输入流</strong> ：把数据从<code>其他设备</code>上读取到<code>内存</code>中的流。</li><li><strong>输出流</strong> ：把数据从<code>内存</code> 中写出到<code>其他设备</code>上的流。</li></ul><p>根据数据的类型分为：<strong>字节流</strong> 和 <strong>字符流</strong>。</p><ul><li><strong>字节流</strong> ：以字节为单位，读写数据的流。</li><li><strong>字符流</strong> ：以字符为单位，读写数据的流。</li></ul><p>分类之后对应的父类</p><table><thead><tr><th></th><th>输入流</th><th>输出流</th></tr></thead><tbody><tr><td>字节流</td><td>字节输入流 <strong>InputStream</strong></td><td>字节输出流 <strong>OutputStream</strong></td></tr><tr><td>字符流</td><td>字符输入流 <strong>Reader</strong></td><td>字符输出流 <strong>Writer</strong></td></tr></tbody></table><p>注：<br>由这四个类的子类名称基本都是以其父类名作为子类名的后缀。<br>如：InputStream 的子类 FileInputStream。<br>如：Reader的子 类 FileReader。</p><h2 id="具体分类"><a href="#具体分类" class="headerlink" title="具体分类"></a>具体分类</h2><table><thead><tr><th align="center">分类</th><th align="center">字节输入流</th><th align="center">字节输出流</th><th align="center">字符输入流</th><th align="center">字符输出流</th></tr></thead><tbody><tr><td align="center">抽象基类</td><td align="center"><em>InputStream</em></td><td align="center"><em>OutputStream</em></td><td align="center"><em>Reader</em></td><td align="center"><em>Writer</em></td></tr><tr><td align="center">访问文件</td><td align="center"><strong>FileInputStream</strong></td><td align="center"><strong>FileOutputStream</strong></td><td align="center"><strong>FileReader</strong></td><td align="center"><strong>FileWriter</strong></td></tr><tr><td align="center">访问数组</td><td align="center"><strong>ByteArrayInputStream</strong></td><td align="center"><strong>ByteArrayOutpuStream</strong></td><td align="center"><strong>CharArrayReader</strong></td><td align="center"><strong>CharArrayWriter</strong></td></tr><tr><td align="center">访问管道</td><td align="center"><strong>PipedInputStream</strong></td><td align="center"><strong>PipedOutputStream</strong></td><td align="center"><strong>PipedReader</strong></td><td align="center"><strong>PipedWr</strong>iter</td></tr><tr><td align="center">访问字符串</td><td align="center"></td><td align="center"></td><td align="center"><strong>StringReader</strong></td><td align="center"><strong>StringWriter</strong></td></tr><tr><td align="center">缓冲流</td><td align="center">BufferedInputStream</td><td align="center">BufferedOutputStream</td><td align="center">BufferedReader</td><td align="center">BufferedWriter</td></tr><tr><td align="center">转换流</td><td align="center"></td><td align="center"></td><td align="center">InputStreamReader</td><td align="center">OutputStreamWriter</td></tr><tr><td align="center">对象流</td><td align="center">ObjectInputStream</td><td align="center">ObjectOutputStream</td><td align="center"></td><td align="center"></td></tr><tr><td align="center">过滤流</td><td align="center"><em>FilterInputStream</em></td><td align="center"><em>FilterOutputStream</em></td><td align="center"><em>FilterReader</em></td><td align="center"><em>FilterWriter</em></td></tr><tr><td align="center">打印流</td><td align="center"></td><td align="center">PrintStream</td><td align="center"></td><td align="center">PrintWriter</td></tr><tr><td align="center">推回输入流</td><td align="center">PushbackInputStream</td><td align="center"></td><td align="center">PushbackReader</td><td align="center"></td></tr><tr><td align="center">数据流</td><td align="center">DataInputStream</td><td align="center">DataOutputStream</td><td align="center"></td><td align="center"></td></tr></tbody></table><p>注：倾斜代表抽象类，无法创建实例，红色表示节点流，必须直接与指定物理节点关联。</p><p><img src="/images/java-io.png" alt="思维导图"></p><h1 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h1><h2 id="File-类"><a href="#File-类" class="headerlink" title="File 类"></a>File 类</h2><ul><li>获取文件属性</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.File;<br><span class="hljs-keyword">import</span> java.util.Date;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-comment">// 指定文件所在的目录</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;D:/&quot;</span>;<br>        <span class="hljs-comment">// 建立 File 变量，并设定由 f 变量引用</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">f</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path, <span class="hljs-string">&quot;test.txt&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;D:\\test.txt文件信息如下：&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;============================================&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;文件长度：&quot;</span> + f.length() + <span class="hljs-string">&quot;字节&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;文件或者目录：&quot;</span> + (f.isFile() ? <span class="hljs-string">&quot;是文件&quot;</span> : <span class="hljs-string">&quot;不是文件&quot;</span>));<br>        System.out.println(<span class="hljs-string">&quot;文件或者目录：&quot;</span> + (f.isDirectory() ? <span class="hljs-string">&quot;是目录&quot;</span> : <span class="hljs-string">&quot;不是目录&quot;</span>));<br>        System.out.println(<span class="hljs-string">&quot;是否可读：&quot;</span> + (f.canRead() ? <span class="hljs-string">&quot;可读取&quot;</span> : <span class="hljs-string">&quot;不可读取&quot;</span>));<br>        System.out.println(<span class="hljs-string">&quot;是否可写：&quot;</span> + (f.canWrite() ? <span class="hljs-string">&quot;可写入&quot;</span> : <span class="hljs-string">&quot;不可写入&quot;</span>));<br>        System.out.println(<span class="hljs-string">&quot;是否隐藏：&quot;</span> + (f.isHidden() ? <span class="hljs-string">&quot;是隐藏文件&quot;</span> : <span class="hljs-string">&quot;不是隐藏文件&quot;</span>));<br>        System.out.println(<span class="hljs-string">&quot;最后修改日期：&quot;</span> + <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(f.lastModified()));<br>        System.out.println(<span class="hljs-string">&quot;文件名称：&quot;</span> + f.getName());<br>        System.out.println(<span class="hljs-string">&quot;文件路径：&quot;</span> + f.getPath());<br>        System.out.println(<span class="hljs-string">&quot;绝对路径：&quot;</span> + f.getAbsolutePath());<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">D:\test.txt文件信息如下：============================================文件长度：0字节文件或者目录：是文件文件或者目录：不是目录是否可读：可读取是否可写：可写入是否隐藏：不是隐藏文件最后修改日期：Tue Sep 27 16:06:10 GMT+08:00 2022文件名称：test.txt文件路径：D:\test.txt绝对路径：D:\test.txt</code></pre><ul><li>创建和删除文件</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.File;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileTest01</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br>        <span class="hljs-comment">// 创建指向文件的 File 对象</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">f</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>);<br>        <span class="hljs-comment">// 判断文件是否存在</span><br>        <span class="hljs-keyword">if</span> (f.exists()) &#123;<br>            <span class="hljs-comment">// 存在则先删除</span><br>            <span class="hljs-type">boolean</span> <span class="hljs-variable">delete</span> <span class="hljs-operator">=</span> f.delete();<br>            System.out.println(delete);<br>        &#125;<br>        <span class="hljs-comment">// 再创建</span><br>        <span class="hljs-type">boolean</span> <span class="hljs-variable">newFile</span> <span class="hljs-operator">=</span> f.createNewFile();<br>        System.out.println(newFile);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">truetrue</code></pre><ul><li>创建和删除目录</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.File;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileTest02</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-comment">// 指定目录位置</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;D:/config/&quot;</span>;<br>        <span class="hljs-comment">// 创建 File 对象</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">f</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path);<br>        <span class="hljs-keyword">if</span> (f.exists()) &#123;<br>            <span class="hljs-type">boolean</span> <span class="hljs-variable">delete</span> <span class="hljs-operator">=</span> f.delete();<br>            System.out.println(delete);<br>        &#125;<br>        <span class="hljs-comment">// 创建目录</span><br>        <span class="hljs-type">boolean</span> <span class="hljs-variable">mkdir</span> <span class="hljs-operator">=</span> f.mkdir();<br>        System.out.println(mkdir);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">truetrue</code></pre><ul><li>遍历目录</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.File;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileTest03</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-comment">// 建立 File 变量,并设定由 f 变量变数引用</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">f</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:/&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;文件名称\t\t文件类型\t\t文件大小&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;===================================================&quot;</span>);<br>        <span class="hljs-comment">// 调用不带参数的 list() 方法</span><br>        String[] fileList = f.list();<br>        <span class="hljs-keyword">assert</span> fileList != <span class="hljs-literal">null</span>;<br>        <span class="hljs-comment">// 遍历返回的字符数组</span><br>        <span class="hljs-keyword">for</span> (String s : fileList) &#123;<br>            System.out.print(s + <span class="hljs-string">&quot;\t\t&quot;</span>);<br>            System.out.print((<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:/&quot;</span>, s)).isFile() ? <span class="hljs-string">&quot;文件&quot;</span> + <span class="hljs-string">&quot;\t\t&quot;</span> : <span class="hljs-string">&quot;文件夹&quot;</span> + <span class="hljs-string">&quot;\t\t&quot;</span>);<br>            System.out.println((<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:/&quot;</span>, s)).length() + <span class="hljs-string">&quot;字节&quot;</span>);<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">文件名称文件类型文件大小===================================================$RECYCLE.BIN文件夹0字节config文件夹0字节data文件夹0字节home文件夹0字节JamWorkspaceAndroid文件夹0字节note文件夹4096字节oracle文件夹4096字节pagefile.sys文件8053063680字节picture文件夹12288字节Program Files文件夹4096字节Program Files (x86)文件夹4096字节project文件夹0字节study文件夹4096字节System Volume Information文件夹0字节test.txt文件192字节test1.txt文件0字节Users文件夹0字节virtual文件夹0字节软件文件夹4096字节</code></pre><h2 id="字节流"><a href="#字节流" class="headerlink" title="字节流"></a>字节流</h2><p>文件的复制（字节流）</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">InputOutputTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span><span class="hljs-keyword">throws</span> IOException &#123;<br>        <span class="hljs-comment">// 源文件和目标文件</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">source</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>) ;<br>        <span class="hljs-type">File</span> <span class="hljs-variable">target</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test1.txt&quot;</span>) ;<br>        <span class="hljs-comment">// 字节输入流和输出流</span><br>        <span class="hljs-type">InputStream</span> <span class="hljs-variable">inStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(source) ;<br>        <span class="hljs-type">OutputStream</span> <span class="hljs-variable">outStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(target) ;<br>        <span class="hljs-comment">// 字节读入和写出</span><br>        <span class="hljs-type">byte</span>[] byteArr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">byte</span>[<span class="hljs-number">1024</span>];<br>        <span class="hljs-type">int</span> readSign ;<br>        <span class="hljs-keyword">while</span> ((readSign = inStream.read(byteArr)) != -<span class="hljs-number">1</span>)&#123;<br>            outStream.write(readSign);<br>        &#125;<br>        <span class="hljs-comment">// 关闭流</span><br>        outStream.close();<br>        inStream.close();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="字符流"><a href="#字符流" class="headerlink" title="字符流"></a>字符流</h2><p>文件的复制（字符流），其速度效率要快于字节流读取，对于非文本文件（视频文件、音频文件、图片），只能使用字节流！</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ReaderWriterTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">// 读文本和写文本</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">readerFile</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>) ;<br>        <span class="hljs-type">File</span> <span class="hljs-variable">writerFile</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test1.txt&quot;</span>) ;<br>        <span class="hljs-comment">// 字符输入和输出流</span><br>        <span class="hljs-type">Reader</span> <span class="hljs-variable">reader</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileReader</span>(readerFile) ;<br>        <span class="hljs-type">Writer</span> <span class="hljs-variable">writer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileWriter</span>(writerFile);<br>        <span class="hljs-comment">// 字符读入和写出</span><br>        <span class="hljs-type">int</span> readSign;<br>        <span class="hljs-keyword">while</span> ((readSign = reader.read()) != -<span class="hljs-number">1</span>) &#123;<br>            writer.write(readSign);<br>        &#125;<br>        writer.flush();<br>        <span class="hljs-comment">// 关闭流</span><br>        writer.close();<br>        reader.close();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="字节缓冲流"><a href="#字节缓冲流" class="headerlink" title="字节缓冲流"></a>字节缓冲流</h2><p>文件的复制（字节缓冲流，加速字节读取）</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">BufferedInputOutputTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">// 源文件 目标文件</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">source</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>);<br>        <span class="hljs-type">File</span> <span class="hljs-variable">target</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test1.txt&quot;</span>);<br>        <span class="hljs-comment">// 缓冲：字节输入流字符输出流</span><br>        <span class="hljs-type">InputStream</span> <span class="hljs-variable">bufInStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedInputStream</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(source));<br>        <span class="hljs-type">OutputStream</span> <span class="hljs-variable">bufOutStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedOutputStream</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(target));<br>        <span class="hljs-comment">// 字节读入和写出</span><br>        <span class="hljs-type">int</span> readSign;<br>        <span class="hljs-keyword">while</span> ((readSign = bufInStream.read()) != -<span class="hljs-number">1</span>) &#123;<br>            bufOutStream.write(readSign);<br>        &#125;<br>        <span class="hljs-comment">// 关闭流</span><br>        bufOutStream.close();<br>        bufInStream.close();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="字符缓冲流"><a href="#字符缓冲流" class="headerlink" title="字符缓冲流"></a>字符缓冲流</h2><p>文件的复制（字符缓冲流，加速字符读取）</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">BufferedReaderWriterTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">// 读文本和写文本</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">readerFile</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>) ;<br>        <span class="hljs-type">File</span> <span class="hljs-variable">writerFile</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;D:\\test1.txt&quot;</span>) ;<br>        <span class="hljs-comment">// 缓冲：字符输入和输出流</span><br>        <span class="hljs-type">BufferedReader</span> <span class="hljs-variable">bufReader</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedReader</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileReader</span>(readerFile)) ;<br>        <span class="hljs-type">BufferedWriter</span> <span class="hljs-variable">bufWriter</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedWriter</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileWriter</span>(writerFile)) ;<br>        <span class="hljs-comment">// 字符读入和写出</span><br>        String line;<br>        <span class="hljs-keyword">while</span> ((line = bufReader.readLine()) != <span class="hljs-literal">null</span>)&#123;<br>            bufWriter.write(line);<br>            bufWriter.newLine();<br>        &#125;<br>        bufWriter.flush();<br>        <span class="hljs-comment">// 关闭流</span><br>        bufWriter.close();<br>        bufReader.close();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="转换流"><a href="#转换流" class="headerlink" title="转换流"></a>转换流</h2><p>转换流可以将字节流读取到的字节，按指定字符集解码成字符。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">InputOutputStreamReaderTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-comment">// 解码，把字节数组变成字符流</span><br>            <span class="hljs-type">InputStreamReader</span> <span class="hljs-variable">isr</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">InputStreamReader</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>));<br>            <span class="hljs-type">BufferedReader</span> <span class="hljs-variable">br</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedReader</span>(isr);<br><br>            <span class="hljs-comment">// 编码，把字符流变成字节数组</span><br>            <span class="hljs-type">FileOutputStream</span> <span class="hljs-variable">fos</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>);<br>            <span class="hljs-comment">// 指定字符集</span><br>            <span class="hljs-type">OutputStreamWriter</span> <span class="hljs-variable">osr</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">OutputStreamWriter</span>(fos, StandardCharsets.UTF_8);<br>            <span class="hljs-type">BufferedWriter</span> <span class="hljs-variable">bw</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedWriter</span>(osr);<br><br>            <span class="hljs-type">int</span> len;<br>            <span class="hljs-type">char</span>[] c = <span class="hljs-keyword">new</span> <span class="hljs-title class_">char</span>[<span class="hljs-number">8</span> * <span class="hljs-number">1024</span>];<br>            <span class="hljs-keyword">while</span> ((len = br.read(c)) != -<span class="hljs-number">1</span>) &#123;<br>                bw.write(c, <span class="hljs-number">0</span>, len);<br>                bw.flush();<br>            &#125;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="数据流"><a href="#数据流" class="headerlink" title="数据流"></a>数据流</h2><p>数据流：用来处理基本数据类型、String、字节数组的数据。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DataInputOutputStream</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception  &#123;<br>        <span class="hljs-type">DataOutputStream</span> <span class="hljs-variable">dataOutputStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DataOutputStream</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>));<br>        dataOutputStream.writeUTF(<span class="hljs-string">&quot;我爱你，而你不知道&quot;</span>);<br>        dataOutputStream.writeBoolean(<span class="hljs-literal">true</span>);<br>        dataOutputStream.writeInt(<span class="hljs-number">12</span>);<br>        dataOutputStream.close();<br><br>        <span class="hljs-type">DataInputStream</span> <span class="hljs-variable">dataInputStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DataInputStream</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>));<br>        System.out.println(dataInputStream.readUTF());<br>        System.out.println(dataInputStream.readBoolean());<br>        System.out.println(dataInputStream.readInt());<br>        dataInputStream.close();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">我爱你，而你不知道true12</code></pre><h2 id="对象流"><a href="#对象流" class="headerlink" title="对象流"></a>对象流</h2><p>序列化：对象转换为流的过程，反序列化：流转换为对象的过程。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ObjectInputOutputStreamTest</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">// 序列化对象</span><br>        <span class="hljs-type">OutputStream</span> <span class="hljs-variable">outStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>);<br>        <span class="hljs-type">ObjectOutputStream</span> <span class="hljs-variable">objOutStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectOutputStream</span>(outStream);<br>        objOutStream.writeObject(<span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>(<span class="hljs-number">1</span>,<span class="hljs-string">&quot;test&quot;</span>));<br>        objOutStream.close();<br><br>        <span class="hljs-comment">// 反序列化对象</span><br>        <span class="hljs-type">InputStream</span> <span class="hljs-variable">inStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(<span class="hljs-string">&quot;D:\\test.txt&quot;</span>);<br>        <span class="hljs-type">ObjectInputStream</span> <span class="hljs-variable">objInStream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectInputStream</span>(inStream) ;<br>        <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> (User) objInStream.readObject();<br>        System.out.println(user);<br>        System.out.println(user.id);<br>        System.out.println(user.name);<br>        inStream.close();<br>    &#125;<br><br>    <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span> &#123;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Integer id ;<br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String name ;<br><br>        <span class="hljs-keyword">public</span> <span class="hljs-title function_">User</span><span class="hljs-params">(<span class="hljs-type">int</span> id, String name)</span> &#123;<br>            <span class="hljs-built_in">this</span>.id = id;<br>            <span class="hljs-built_in">this</span>.name = name;<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">ObjectInputOutputStreamTest$User@47f64731test</code></pre><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://baike.baidu.com/item/java.io/5179754">Java IO 百度百科</a></li><li><a href="https://www.cnblogs.com/yichunguo/p/11775270.htm">史上最骚最全最详细的 IO 流教程，没有之一</a></li><li><a href="http://www.cyc2018.xyz/Java/Java%20IO.html">CS Notes Java IO</a></li><li><a href="http://www.cyc2018.xyz/Java/Java%20IO.html">Java Note IO 流</a></li><li><a href="https://blog.csdn.net/weixin_44050211/article/details/126909966">Java 基础 IO流【示例篇】</a></li><li><a href="http://c.biancheng.net/view/1133.html">Java File类（文件操作类）详解</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;h2 id=&quot;IO&quot;&gt;&lt;a href=&quot;#IO&quot; class=&quot;headerlink&quot; title=&quot;IO&quot;&gt;&lt;/a&gt;IO&lt;/h2&gt;&lt;p&gt;通过&lt;</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>Java 自定义注解</title>
    <link href="http://www.loquy.cn/posts/f96fd70c.html"/>
    <id>http://www.loquy.cn/posts/f96fd70c.html</id>
    <published>2022-09-13T03:54:00.000Z</published>
    <updated>2022-09-13T03:59:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="注解知识点"><a href="#注解知识点" class="headerlink" title="注解知识点"></a>注解知识点</h1><ul><li>思维导图</li></ul><p><img src="/images/javaAnnotation.jpg" alt="Java注解"></p><h1 id="自定义注解"><a href="#自定义注解" class="headerlink" title="自定义注解"></a>自定义注解</h1><h2 id="编写规则"><a href="#编写规则" class="headerlink" title="编写规则"></a>编写规则</h2><ol><li>Annotation 型定义为 @interface，所有的 Annotation 会自动继承 java.lang.Annotation 这一接口，并且不能再去继承别的类或是接口。</li><li>参数成员只能用 public 或默认(default) 这两个访问权修饰。</li><li>参数成员只能用基本类型 byte、short、char、int、long、float、double、boolean 八种基本数据类型和 String、Enum、Class、annotations 等数据类型，以及这一些类型的数组。</li><li>要获取类方法和字段的注解信息，必须通过 Java 的反射技术来获取 Annotation 对象，因为你除此之外没有别的获取注解对象的方法。</li></ol><h2 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.lang.annotation.ElementType;<br><span class="hljs-keyword">import</span> java.lang.annotation.Retention;<br><span class="hljs-keyword">import</span> java.lang.annotation.RetentionPolicy;<br><span class="hljs-keyword">import</span> java.lang.annotation.Target;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Target(ElementType.FIELD)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> FieldInfo &#123;<br>    String <span class="hljs-title function_">description</span><span class="hljs-params">()</span>;<br>    <span class="hljs-type">int</span> <span class="hljs-title function_">length</span><span class="hljs-params">()</span>;<br>&#125;<br><br></code></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.lang.reflect.Field;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FieldInfoTest</span> &#123;<br><br>    <span class="hljs-meta">@FieldInfo(description = &quot;用户名&quot;, length = 10)</span><br>    <span class="hljs-keyword">private</span> String username;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-comment">// 获取类模板</span><br>        Class&lt;FieldInfoTest&gt; c = FieldInfoTest.class;<br><br>        <span class="hljs-comment">// 获取所有字段</span><br>        <span class="hljs-keyword">for</span>(Field f : c.getDeclaredFields())&#123;<br>            <span class="hljs-comment">// 判断这个字段是否有 FieldInfo 注解</span><br>            <span class="hljs-keyword">if</span>(f.isAnnotationPresent(FieldInfo.class))&#123;<br>                <span class="hljs-type">FieldInfo</span> <span class="hljs-variable">annotation</span> <span class="hljs-operator">=</span> f.getAnnotation(FieldInfo.class);<br>                System.out.println(<br>                        <span class="hljs-string">&quot;字段:[&quot;</span> + f.getName() + <span class="hljs-string">&quot;],&quot;</span> +<br>                        <span class="hljs-string">&quot;描述:[&quot;</span> + annotation.description() + <span class="hljs-string">&quot;],&quot;</span> +<br>                        <span class="hljs-string">&quot;长度:[&quot;</span> + annotation.length() +<span class="hljs-string">&quot;]&quot;</span><br>                );<br>            &#125;<br>        &#125;<br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure><p>输出：</p><pre><code class="hljs">字段：[username]，描述：[用户名]，长度：[10]</code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;注解知识点&quot;&gt;&lt;a href=&quot;#注解知识点&quot; class=&quot;headerlink&quot; title=&quot;注解知识点&quot;&gt;&lt;/a&gt;注解知识点&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;思维导图&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/javaAnnotation.</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>MySQL 行转列</title>
    <link href="http://www.loquy.cn/posts/aad432c8.html"/>
    <id>http://www.loquy.cn/posts/aad432c8.html</id>
    <published>2022-09-01T06:49:46.000Z</published>
    <updated>2022-09-01T06:49:46.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="列表数据"><a href="#列表数据" class="headerlink" title="列表数据"></a>列表数据</h1><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs sql">mysql<span class="hljs-operator">&gt;</span> <span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> score;<br><span class="hljs-operator">+</span><span class="hljs-comment">----+--------+---------+-------+</span><br><span class="hljs-operator">|</span> id <span class="hljs-operator">|</span> name   <span class="hljs-operator">|</span> subject <span class="hljs-operator">|</span> score <span class="hljs-operator">|</span><br><span class="hljs-operator">+</span><span class="hljs-comment">----+--------+---------+-------+</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">1</span> <span class="hljs-operator">|</span> 张三   <span class="hljs-operator">|</span> 语文    <span class="hljs-operator">|</span>    <span class="hljs-number">10</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">2</span> <span class="hljs-operator">|</span> 张三   <span class="hljs-operator">|</span> 数学    <span class="hljs-operator">|</span>    <span class="hljs-number">30</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">3</span> <span class="hljs-operator">|</span> 张三   <span class="hljs-operator">|</span> 英语    <span class="hljs-operator">|</span>    <span class="hljs-number">40</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">4</span> <span class="hljs-operator">|</span> 张三   <span class="hljs-operator">|</span> 化学    <span class="hljs-operator">|</span>    <span class="hljs-number">50</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">5</span> <span class="hljs-operator">|</span> 李四   <span class="hljs-operator">|</span> 语文    <span class="hljs-operator">|</span>    <span class="hljs-number">60</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">6</span> <span class="hljs-operator">|</span> 李四   <span class="hljs-operator">|</span> 数学    <span class="hljs-operator">|</span>    <span class="hljs-number">70</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">7</span> <span class="hljs-operator">|</span> 李四   <span class="hljs-operator">|</span> 英语    <span class="hljs-operator">|</span>    <span class="hljs-number">80</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">8</span> <span class="hljs-operator">|</span> 王五   <span class="hljs-operator">|</span> 英语    <span class="hljs-operator">|</span>    <span class="hljs-number">90</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span>  <span class="hljs-number">9</span> <span class="hljs-operator">|</span> 王五   <span class="hljs-operator">|</span> 语文    <span class="hljs-operator">|</span>   <span class="hljs-number">100</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span> <span class="hljs-number">10</span> <span class="hljs-operator">|</span> 王五   <span class="hljs-operator">|</span> 数学    <span class="hljs-operator">|</span>   <span class="hljs-number">110</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span> <span class="hljs-number">11</span> <span class="hljs-operator">|</span> 王五   <span class="hljs-operator">|</span> 数学    <span class="hljs-operator">|</span>   <span class="hljs-number">120</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">+</span><span class="hljs-comment">----+--------+---------+-------+</span><br></code></pre></td></tr></table></figure><h1 id="行转列写法"><a href="#行转列写法" class="headerlink" title="行转列写法"></a>行转列写法</h1><ul><li>CASE 函数定义和用法</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CASE</span><br>    <span class="hljs-keyword">WHEN</span> 条件<span class="hljs-number">1</span> <span class="hljs-keyword">THEN</span> 结果<span class="hljs-number">1</span><br>    <span class="hljs-keyword">WHEN</span> 条件<span class="hljs-number">2</span> <span class="hljs-keyword">THEN</span> 结果<span class="hljs-number">2</span><br>    <span class="hljs-keyword">WHEN</span> 条件N <span class="hljs-keyword">THEN</span> 结果N<br>    <span class="hljs-keyword">ELSE</span> 结果<br><span class="hljs-keyword">END</span>;<br></code></pre></td></tr></table></figure><ul><li><p>查询语句：</p><p>按 name 字段进行 group by 分组，分组后使用 case 函数达成行转列，如果符合条件的 subject 字段对应有多行数据，取其中最大的 score 字段的值，如果不符合条件则设为 0。</p><p>要注意在 case 函数中使用的字段不可用来 group by 分组，选取其他具有相同值的字段进行分组。</p></li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> `name`,<br><span class="hljs-built_in">max</span>( <span class="hljs-keyword">CASE</span> `subject` <span class="hljs-keyword">WHEN</span> <span class="hljs-string">&#x27;语文&#x27;</span> <span class="hljs-keyword">THEN</span> score <span class="hljs-keyword">ELSE</span> <span class="hljs-number">0</span> <span class="hljs-keyword">END</span> ) <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;语文&#x27;</span>,<br><span class="hljs-built_in">max</span>( <span class="hljs-keyword">CASE</span> `subject` <span class="hljs-keyword">WHEN</span> <span class="hljs-string">&#x27;数学&#x27;</span> <span class="hljs-keyword">THEN</span> score <span class="hljs-keyword">ELSE</span> <span class="hljs-number">0</span> <span class="hljs-keyword">END</span> ) <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;数学&#x27;</span>,<br><span class="hljs-built_in">max</span>( <span class="hljs-keyword">CASE</span> `subject` <span class="hljs-keyword">WHEN</span> <span class="hljs-string">&#x27;英语&#x27;</span> <span class="hljs-keyword">THEN</span> score <span class="hljs-keyword">ELSE</span> <span class="hljs-number">0</span> <span class="hljs-keyword">END</span> ) <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;英语&#x27;</span>,<br><span class="hljs-built_in">max</span>( <span class="hljs-keyword">CASE</span> `subject` <span class="hljs-keyword">WHEN</span> <span class="hljs-string">&#x27;化学&#x27;</span> <span class="hljs-keyword">THEN</span> score <span class="hljs-keyword">ELSE</span> <span class="hljs-number">0</span> <span class="hljs-keyword">END</span> ) <span class="hljs-keyword">AS</span> <span class="hljs-string">&#x27;化学&#x27;</span> <br><span class="hljs-keyword">FROM</span><br>score <br><span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span><br>`name`<br></code></pre></td></tr></table></figure><ul><li>查询结果：</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-operator">+</span><span class="hljs-comment">--------+--------+--------+--------+--------+</span><br><span class="hljs-operator">|</span> name   <span class="hljs-operator">|</span> 语文   <span class="hljs-operator">|</span> 数学   <span class="hljs-operator">|</span> 英语   <span class="hljs-operator">|</span> 化学   <span class="hljs-operator">|</span><br><span class="hljs-operator">+</span><span class="hljs-comment">--------+--------+--------+--------+--------+</span><br><span class="hljs-operator">|</span> 张三   <span class="hljs-operator">|</span>     <span class="hljs-number">10</span> <span class="hljs-operator">|</span>     <span class="hljs-number">30</span> <span class="hljs-operator">|</span>     <span class="hljs-number">40</span> <span class="hljs-operator">|</span>     <span class="hljs-number">50</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span> 李四   <span class="hljs-operator">|</span>     <span class="hljs-number">60</span> <span class="hljs-operator">|</span>     <span class="hljs-number">70</span> <span class="hljs-operator">|</span>     <span class="hljs-number">80</span> <span class="hljs-operator">|</span>      <span class="hljs-number">0</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">|</span> 王五   <span class="hljs-operator">|</span>    <span class="hljs-number">100</span> <span class="hljs-operator">|</span>    <span class="hljs-number">120</span> <span class="hljs-operator">|</span>     <span class="hljs-number">90</span> <span class="hljs-operator">|</span>      <span class="hljs-number">0</span> <span class="hljs-operator">|</span><br><span class="hljs-operator">+</span><span class="hljs-comment">--------+--------+--------+--------+--------+</span><br></code></pre></td></tr></table></figure><h1 id="创建表和导入数据"><a href="#创建表和导入数据" class="headerlink" title="创建表和导入数据"></a>创建表和导入数据</h1><ul><li>表结构：</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `score` (<br>  `id` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `name` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `subject` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `score` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)<br>) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;<br></code></pre></td></tr></table></figure><ul><li>测试数据：</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-string">&#x27;语文&#x27;</span>, <span class="hljs-number">10</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-string">&#x27;数学&#x27;</span>, <span class="hljs-number">30</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-string">&#x27;英语&#x27;</span>, <span class="hljs-number">40</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-string">&#x27;张三&#x27;</span>, <span class="hljs-string">&#x27;化学&#x27;</span>, <span class="hljs-number">50</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-string">&#x27;李四&#x27;</span>, <span class="hljs-string">&#x27;语文&#x27;</span>, <span class="hljs-number">60</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">6</span>, <span class="hljs-string">&#x27;李四&#x27;</span>, <span class="hljs-string">&#x27;数学&#x27;</span>, <span class="hljs-number">70</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">7</span>, <span class="hljs-string">&#x27;李四&#x27;</span>, <span class="hljs-string">&#x27;英语&#x27;</span>, <span class="hljs-number">80</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">8</span>, <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-string">&#x27;英语&#x27;</span>, <span class="hljs-number">90</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-string">&#x27;语文&#x27;</span>, <span class="hljs-number">100</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">10</span>, <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-string">&#x27;数学&#x27;</span>, <span class="hljs-number">110</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `score` (`id`, `name`, `subject`, `score`) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">11</span>, <span class="hljs-string">&#x27;王五&#x27;</span>, <span class="hljs-string">&#x27;数学&#x27;</span>, <span class="hljs-number">120</span>);<br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">MySQL 中使用 CASE 函数达成行转列。</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="MySQL" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/MySQL/"/>
    
    
    <category term="SQL" scheme="http://www.loquy.cn/tags/SQL/"/>
    
    <category term="MySQL" scheme="http://www.loquy.cn/tags/MySQL/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot 中使用 Hutool 跨数据库增删改查</title>
    <link href="http://www.loquy.cn/posts/f2cc0d20.html"/>
    <id>http://www.loquy.cn/posts/f2cc0d20.html</id>
    <published>2022-08-26T03:36:47.000Z</published>
    <updated>2022-08-26T03:36:47.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><pre><code class="hljs">Hutool 是一个小而全的Java工具类库，通过静态方法封装，降低相关 API 的学习成本，提高工作效率，使 Java 拥有函数式语言般的优雅，让 Java 语言也可以“甜甜的”。Hutool 中的工具方法来自每个用户的精雕细琢，它涵盖了 Java 开发底层代码中的方方面面，它既是大型项目开发中解决小问题的利器，也是小型项目中的效率担当；Hutool 是项目中“util”包友好的替代，它节省了开发人员对项目中公用类和公用工具方法的封装时间，使开发专注于业务，同时可以最大限度的避免封装不完善带来的 bug。</code></pre><h1 id="表结构"><a href="#表结构" class="headerlink" title="表结构"></a>表结构</h1><p>我们以 MySQL 为例，分别在两个数据库创建名为 test 和 test_1 的数据库，执行以下 sql 语句创建 user 表。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `<span class="hljs-keyword">user</span>` (<br>  `id` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `name` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `pwd` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)<br>) ENGINE<span class="hljs-operator">=</span>INNODB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;<br></code></pre></td></tr></table></figure><h1 id="项目结构"><a href="#项目结构" class="headerlink" title="项目结构"></a>项目结构</h1><p><img src="https://www.loquy.cn/images/spring-boot-crossdatabase.jpg"></p><pre><code class="hljs">spring-boot-demo│  .gitignore│  pom.xml│  README.md│  spring-boot-demo.iml│├─spring-boot-crossdatabase│  │  .gitignore│  │  pom.xml│  │  spring-boot-crossdatabase.iml│  ││  ├─src│  │  ├─main│  │  │  ├─java│  │  │  │  └─com│  │  │  │      └─example│  │  │  │          └─crossdatabase│  │  │  │              │  SpringBootCrossdatabaseApplication.java│  │  │  │              ││  │  │  │              └─utils│  │  │  │                      CrossDatabaseUtils.java│  │  │  ││  │  │  └─resources│  │  │      │  application.properties│  │  │      ││  │  │      └─config│  │  │              db.setting│  │  ││  │  └─test│  │      └─java│  │          └─com│  │              └─example│  │                  └─crossdatabase│  │                          SpringBootCrossdatabaseApplicationTests.java│├─spring-boot-hibernate│└─spring-boot-mongodb</code></pre><h1 id="引入依赖"><a href="#引入依赖" class="headerlink" title="引入依赖"></a>引入依赖</h1><p>在项目的 pom.xml 的 dependencies 中加入以下内容:</p><ul><li>导入 hutool-all 包</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cn.hutool<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hutool-all<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.8.5<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure><ul><li>引入 MySQL JDBC 驱动 jar</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>$&#123;mysql.version&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure><h1 id="数据库配置"><a href="#数据库配置" class="headerlink" title="数据库配置"></a>数据库配置</h1><p>在 src&#x2F;main&#x2F;resources&#x2F;config 目录下添加 db.setting 文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs setting">[test]<br>url = jdbc:mysql://localhost:3306/test?serverTimezone=UTC&amp;setUnicode=true&amp;charterEncoding=utf-8<br>username = root<br>password = root<br>driver = com.mysql.jdbc.Driver<br><br>[test_1]<br>url = jdbc:mysql://192.168.8.117:3306/test_1?serverTimezone=UTC&amp;setUnicode=true&amp;charterEncoding=utf-8<br>username = root<br>password = root<br>driver = com.mysql.jdbc.Driver<br></code></pre></td></tr></table></figure><h1 id="编写工具类"><a href="#编写工具类" class="headerlink" title="编写工具类"></a>编写工具类</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.crossdatabase.utils;<br><br><span class="hljs-keyword">import</span> cn.hutool.db.Db;<br><span class="hljs-keyword">import</span> cn.hutool.db.ds.DSFactory;<br><br><span class="hljs-keyword">import</span> javax.sql.DataSource;<br><span class="hljs-keyword">import</span> java.util.HashMap;<br><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CrossDatabaseUtils</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> HashMap&lt;String, Db&gt; DBS = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;();<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 初始化数据源</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Db <span class="hljs-title function_">initDb</span><span class="hljs-params">(String dataBase)</span> &#123;<br>        Db db;<br>        <span class="hljs-keyword">if</span> (DBS.containsKey(dataBase)) &#123;<br>            db = DBS.get(dataBase);<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-type">DataSource</span> <span class="hljs-variable">ds</span> <span class="hljs-operator">=</span> DSFactory.get(dataBase);<br>            db = Db.use(ds);<br>            DBS.put(dataBase,db);<br>        &#125;<br>        <span class="hljs-keyword">return</span> db;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.crossdatabase;<br><br><span class="hljs-keyword">import</span> cn.hutool.db.Db;<br><span class="hljs-keyword">import</span> cn.hutool.db.Entity;<br><span class="hljs-keyword">import</span> com.example.crossdatabase.utils.CrossDatabaseUtils;<br><span class="hljs-keyword">import</span> org.junit.jupiter.api.Test;<br><span class="hljs-keyword">import</span> org.springframework.boot.test.context.SpringBootTest;<br><br><span class="hljs-keyword">import</span> java.sql.SQLException;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-meta">@SpringBootTest</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">SpringBootCrossdatabaseApplicationTests</span> &#123;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">contextLoads</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Db</span> <span class="hljs-variable">testDb</span> <span class="hljs-operator">=</span> CrossDatabaseUtils.initDb(<span class="hljs-string">&quot;test&quot;</span>);<br>            <span class="hljs-type">Db</span> <span class="hljs-variable">testDb1</span> <span class="hljs-operator">=</span> CrossDatabaseUtils.initDb(<span class="hljs-string">&quot;test_1&quot;</span>);<br>            System.out.println(<span class="hljs-string">&quot;============test=============&quot;</span>);<br>            crud(testDb);<br>            System.out.println(<span class="hljs-string">&quot;============test_1=============&quot;</span>);<br>            crud(testDb1);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">crud</span><span class="hljs-params">(Db db)</span> <span class="hljs-keyword">throws</span> SQLException &#123;<br>        <span class="hljs-comment">// 删除所有</span><br>        <span class="hljs-type">int</span> <span class="hljs-variable">deleteAll</span> <span class="hljs-operator">=</span> db.execute(<span class="hljs-string">&quot;delete from user&quot;</span>);<br>        <span class="hljs-comment">// 新增</span><br>        <span class="hljs-type">int</span> <span class="hljs-variable">insert</span> <span class="hljs-operator">=</span> db.execute(<span class="hljs-string">&quot;insert into user values (?, ?, ?)&quot;</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&quot;张三&quot;</span>, <span class="hljs-number">123123</span>);<br>        <span class="hljs-type">int</span> <span class="hljs-variable">insert1</span> <span class="hljs-operator">=</span> db.execute(<span class="hljs-string">&quot;insert into user values (?, ?, ?)&quot;</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&quot;李四&quot;</span>, <span class="hljs-number">123123</span>);<br>        <span class="hljs-comment">// 更新</span><br>        <span class="hljs-type">int</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> db.execute(<span class="hljs-string">&quot;update user set pwd = ? where name = ?&quot;</span>, <span class="hljs-number">123456</span>, <span class="hljs-string">&quot;张三&quot;</span>);<br>        <span class="hljs-comment">// 删除</span><br>        <span class="hljs-type">int</span> <span class="hljs-variable">delete</span> <span class="hljs-operator">=</span> db.execute(<span class="hljs-string">&quot;delete from user where name = ?&quot;</span>, <span class="hljs-string">&quot;张三&quot;</span>);<br>        <span class="hljs-comment">// 查询</span><br>        List&lt;Entity&gt; query = db.query(<span class="hljs-string">&quot;select * from user&quot;</span>);<br>        System.out.println(deleteAll);<br>        System.out.println(insert);<br>        System.out.println(insert1);<br>        System.out.println(update);<br>        System.out.println(delete);<br>        System.out.println(query);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出<br><img src="https://www.loquy.cn/images/SpringBootCrossdatabaseApplicationTests.jpg"></p><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p><a href="https://github.com/loquy/spring-boot-demo">参见此仓库</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Hutool 是一个小而全的Java工具类库，通过静态方法封装，降低相关 API 的学习成本，
提</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="Hutool" scheme="http://www.loquy.cn/tags/Hutool/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot 中使用 Hibernate</title>
    <link href="http://www.loquy.cn/posts/fb332309.html"/>
    <id>http://www.loquy.cn/posts/fb332309.html</id>
    <published>2022-08-11T01:20:09.000Z</published>
    <updated>2022-08-11T01:20:09.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><pre><code class="hljs">Hibernate是一个开放源代码的对象关系映射框架，它对JDBC进行了非常轻量级的对象封装，它将POJO与数据库表建立映射关系，是一个全自动的orm框架，hibernate可以自动生成SQL语句，自动执行，使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合，既可以在Java的客户端程序使用，也可以在Servlet/JSP的Web应用中使用，最具革命意义的是，Hibernate可以在应用EJB的JaveEE架构中取代CMP，完成数据持久化的重任。</code></pre><h1 id="表结构"><a href="#表结构" class="headerlink" title="表结构"></a>表结构</h1><p>创建名为 hibernate 数据库，执行以下 sql 语句创建 user 表。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `<span class="hljs-keyword">user</span>` (<br>  `id` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `name` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `pwd` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)<br>) ENGINE<span class="hljs-operator">=</span>MyISAM <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;<br></code></pre></td></tr></table></figure><h1 id="Maven-项目结构"><a href="#Maven-项目结构" class="headerlink" title="Maven 项目结构"></a>Maven 项目结构</h1><p><img src="https://www.loquy.cn/images/spring-boot-hibernate.jpg"></p><pre><code class="hljs">spring-boot-demo│  .gitignore│  pom.xml│  README.md│├─spring-boot-hibernate│  │  .gitignore│  │  pom.xml│  ││  ├─src│  │  ├─main│  │  │  ├─java│  │  │  │  └─com│  │  │  │      └─example│  │  │  │          └─hibernate│  │  │  │              │  SpringBootHibernateApplication.java│  │  │  │              ││  │  │  │              ├─config│  │  │  │              │      DataSourceConfig.java│  │  │  │              ││  │  │  │              ├─dao│  │  │  │              │  │  UserDao.java│  │  │  │              │  ││  │  │  │              │  └─common│  │  │  │              │          BaseDao.java│  │  │  │              │          BaseDaoImpl.java│  │  │  │              │          Page.java│  │  │  │              ││  │  │  │              └─entity│  │  │  │                      User.java│  │  │  ││  │  │  └─resources│  │  │          application.properties│  │  ││  │  └─test│  │      └─java│  │          └─com│  │              └─example│  │                  └─hibernate│  │                          SpringBootHibernateApplicationTests.java│└─spring-boot-mongodb</code></pre><p>​</p><h1 id="Pom-xml-依赖配置"><a href="#Pom-xml-依赖配置" class="headerlink" title="Pom.xml 依赖配置"></a>Pom.xml 依赖配置</h1><ul><li>spring-boot-demo</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.7.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>pom<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modules</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">module</span>&gt;</span>spring-boot-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">module</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">modules</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">optional</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">optional</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cn.hutool<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hutool-all<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.8.5<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.commons<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>commons-lang3<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.8.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">excludes</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">exclude</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">exclude</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">excludes</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br><br></code></pre></td></tr></table></figure><ul><li>spring-boot-hibernate<ul><li>导入 hibernate 核心的对象关系映射（简称ORM）功能的包</li><li>导入使用 hibernate 实现 java 持久化接口（简称JPA）的包</li></ul></li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-hibernate<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>spring-boot-hibernate<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>spring-boot-hibernate<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.hibernate.javax.persistence<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hibernate-jpa-2.1-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0.2.Final<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.hibernate<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>hibernate-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.6.9.Final<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework/spring-orm --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-orm<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.22<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br><br></code></pre></td></tr></table></figure><h1 id="Application-properties-配置"><a href="#Application-properties-配置" class="headerlink" title="Application.properties 配置"></a>Application.properties 配置</h1><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">spring.datasource.username</span>=<span class="hljs-string">root</span><br><span class="hljs-attr">spring.datasource.password</span>=<span class="hljs-string">root</span><br><span class="hljs-attr">spring.datasource.url</span>=<span class="hljs-string">jdbc:mysql://localhost:3306/hibernate?serverTimezone=UTC&amp;setUnicode=true&amp;charterEncoding=utf-8</span><br><span class="hljs-attr">spring.datasource.driver-class-name</span>=<span class="hljs-string">com.mysql.cj.jdbc.Driver</span><br></code></pre></td></tr></table></figure><h1 id="Entity-对象"><a href="#Entity-对象" class="headerlink" title="Entity 对象"></a>Entity 对象</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate.entity;<br><br><span class="hljs-keyword">import</span> javax.persistence.*;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Entity</span><br><span class="hljs-meta">@Table(name = &quot;user&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> &#123;<br><br>    <span class="hljs-meta">@Id</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> id;<br><br>    <span class="hljs-keyword">private</span> String name;<br><br>    <span class="hljs-keyword">private</span> String pwd;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">User</span><span class="hljs-params">()</span> &#123;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">User</span><span class="hljs-params">(<span class="hljs-type">int</span> id, String name, String pwd)</span> &#123;<br>        <span class="hljs-built_in">this</span>.id = id;<br>        <span class="hljs-built_in">this</span>.name = name;<br>        <span class="hljs-built_in">this</span>.pwd = pwd;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> &#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getPwd</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> pwd;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setPwd</span><span class="hljs-params">(String pwd)</span> &#123;<br>        <span class="hljs-built_in">this</span>.pwd = pwd;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;User&#123;&quot;</span> +<br>                <span class="hljs-string">&quot;id=&quot;</span> + id +<br>                <span class="hljs-string">&quot;, name=&#x27;&quot;</span> + name + <span class="hljs-string">&#x27;\&#x27;&#x27;</span> +<br>                <span class="hljs-string">&quot;, pwd=&#x27;&quot;</span> + pwd + <span class="hljs-string">&#x27;\&#x27;&#x27;</span> +<br>                <span class="hljs-string">&#x27;&#125;&#x27;</span>;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="DataSource-数据源配置"><a href="#DataSource-数据源配置" class="headerlink" title="DataSource 数据源配置"></a>DataSource 数据源配置</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate.config;<br><br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Value;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;<br><span class="hljs-keyword">import</span> org.springframework.jdbc.datasource.DriverManagerDataSource;<br><br><span class="hljs-keyword">import</span> java.util.Properties;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DataSourceConfig</span> &#123;<br><br>    <span class="hljs-meta">@Value(&quot;$&#123;spring.datasource.url&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String dbUrl;<br><br>    <span class="hljs-meta">@Value(&quot;$&#123;spring.datasource.username&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String username;<br><br>    <span class="hljs-meta">@Value(&quot;$&#123;spring.datasource.password&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String password;<br><br>    <span class="hljs-meta">@Value(&quot;$&#123;spring.datasource.driver-class-name&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String driverClassName;<br><br>    <span class="hljs-meta">@Bean(name = &quot;datasource&quot;)</span><br>    <span class="hljs-keyword">public</span> DriverManagerDataSource <span class="hljs-title function_">dataSource</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-type">DriverManagerDataSource</span> <span class="hljs-variable">dataSource</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DriverManagerDataSource</span>();<br>        dataSource.setDriverClassName(driverClassName);<br>        dataSource.setUrl(dbUrl);<br>        dataSource.setUsername(username);<br>        dataSource.setPassword(password);<br><br>        <span class="hljs-type">Properties</span> <span class="hljs-variable">propertiesJpa</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Properties</span>();<br>        dataSource.setConnectionProperties(propertiesJpa);<br>        <span class="hljs-keyword">return</span> dataSource;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="Dao-层封装-CRUD"><a href="#Dao-层封装-CRUD" class="headerlink" title="Dao 层封装 CRUD"></a>Dao 层封装 CRUD</h1><h2 id="JPA-实体管理器（EntityManager）"><a href="#JPA-实体管理器（EntityManager）" class="headerlink" title="JPA 实体管理器（EntityManager）"></a>JPA 实体管理器（EntityManager）</h2><pre><code class="hljs">实体管理器（EntityManager）用于管理系统中的实体，它是实体与数据库之间的桥梁，通过调用实体管理器的相关方法可以把实体持久化到数据库中，同时也可以把数据库中的记录打包成实体对象。</code></pre><p>配置好数据源后可以通过 @PersistenceContext 注解注入 EntityManager 到上下文里管理实体，也可以执行原始的sql查询语句。<br>详情查看此教程 <a href="https://www.w3cschool.cn/java/jpa-entitymanager.html">JPA 实体管理器</a></p><h2 id="通用-BaseDao"><a href="#通用-BaseDao" class="headerlink" title="通用 BaseDao"></a>通用 BaseDao</h2><ul><li>BaseDao</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate.dao.common;<br><br><br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The interface Base dao.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">BaseDao</span>&lt;T&gt; &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Insert.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> model the model</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">insert</span><span class="hljs-params">(Object model)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Update t.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> entity the entity</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the t</span><br><span class="hljs-comment">     */</span><br>    T <span class="hljs-title function_">update</span><span class="hljs-params">(T entity)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Delete.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> model the model</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">delete</span><span class="hljs-params">(Object model)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Find one t.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> primaryKey  the primary key</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the t</span><br><span class="hljs-comment">     */</span><br>    T <span class="hljs-title function_">findOne</span><span class="hljs-params">(Object primaryKey)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Find all list.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment">     */</span><br>    List&lt;T&gt; <span class="hljs-title function_">findAll</span><span class="hljs-params">()</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取查询列表</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> queryStr    the query str</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 返回的是list&lt;Entity&gt; 对象</span><br><span class="hljs-comment">     */</span><br>    List&lt;T&gt; <span class="hljs-title function_">getNativeQueryList</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String queryStr)</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取查询分页列表</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> queryStr    the query str</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> page        the page</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 返回的是Page&lt;list&lt;Entity&gt;&gt; 对象</span><br><span class="hljs-comment">     */</span><br>    Page&lt;T&gt; <span class="hljs-title function_">getNativeQueryListByPage</span><span class="hljs-params">(String queryStr, Page&lt;T&gt; page)</span>;<br><br>&#125;<br><br></code></pre></td></tr></table></figure><ul><li>BaseDaoImpl</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate.dao.common;<br><br><span class="hljs-keyword">import</span> cn.hutool.core.bean.BeanUtil;<br><span class="hljs-keyword">import</span> org.hibernate.query.internal.NativeQueryImpl;<br><span class="hljs-keyword">import</span> org.hibernate.transform.Transformers;<br><span class="hljs-keyword">import</span> org.springframework.util.Assert;<br><br><span class="hljs-keyword">import</span> javax.persistence.EntityManager;<br><span class="hljs-keyword">import</span> javax.persistence.NoResultException;<br><span class="hljs-keyword">import</span> javax.persistence.PersistenceContext;<br><span class="hljs-keyword">import</span> javax.persistence.Query;<br><span class="hljs-keyword">import</span> java.math.BigDecimal;<br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">BaseDaoImpl</span>&lt;T&gt; <span class="hljs-keyword">implements</span> <span class="hljs-title class_">BaseDao</span>&lt;T&gt; &#123;<br><br>    <span class="hljs-meta">@PersistenceContext</span><br>    <span class="hljs-keyword">private</span> EntityManager entityManager;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Class&lt;T&gt; entityClass;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">BaseDaoImpl</span><span class="hljs-params">(Class&lt;T&gt; entityClass)</span> &#123;<br>        <span class="hljs-built_in">this</span>.entityClass = entityClass;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insert</span><span class="hljs-params">(Object model)</span> &#123;<br>        <span class="hljs-built_in">this</span>.entityManager.persist(model);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> T <span class="hljs-title function_">update</span><span class="hljs-params">(T entity)</span> &#123;<br>        <span class="hljs-keyword">return</span> entityManager.merge(entity);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">delete</span><span class="hljs-params">(Object model)</span> &#123;<br>        <span class="hljs-built_in">this</span>.entityManager.remove(model);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> T <span class="hljs-title function_">findOne</span><span class="hljs-params">(Object primaryKey)</span> &#123;<br>        <span class="hljs-keyword">return</span> entityManager.find(entityClass, primaryKey);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-meta">@SuppressWarnings(&quot;unchecked&quot;)</span><br>    <span class="hljs-keyword">public</span>  List&lt;T&gt; <span class="hljs-title function_">findAll</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.entityManager.createQuery(<span class="hljs-string">&quot;select obj from &quot;</span> + entityClass.getName() + <span class="hljs-string">&quot; obj&quot;</span>).getResultList();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取查询列表</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 返回的是list&lt;Entity&gt;对象</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-meta">@SuppressWarnings(&quot;unchecked&quot;)</span><br>    <span class="hljs-keyword">public</span>  List&lt;T&gt; <span class="hljs-title function_">getNativeQueryList</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String queryStr)</span> &#123;<br>        <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> createNativeQuery(queryStr);<br>        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);<br>        List&lt;T&gt; tmpResult = query.getResultList();<br>        List&lt;T&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        <span class="hljs-keyword">for</span> (Object object : tmpResult) &#123;<br>            result.add(BeanUtil.toBean(object, entityClass));<br>        &#125;<br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取查询分页列表</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 返回的是Page&lt;list&lt;Entity&gt;&gt; 对象</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-meta">@SuppressWarnings(&quot;unchecked&quot;)</span><br>    <span class="hljs-keyword">public</span>  Page&lt;T&gt; <span class="hljs-title function_">getNativeQueryListByPage</span><span class="hljs-params">(String queryStr, Page&lt;T&gt; page)</span> &#123;<br>        queryStr += page.getOrderString();<br><br>        <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> createNativeQuery(queryStr);<br>        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);<br><br>        <span class="hljs-type">int</span> <span class="hljs-variable">totalCount</span> <span class="hljs-operator">=</span> countSqlResult(queryStr).intValue();<br>        page.setTotalCount(totalCount);<br>        <span class="hljs-keyword">if</span> (totalCount == <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">return</span> page;<br>        &#125;<br>        setPageParameter(query, page);<br>        List&lt;T&gt; tmpResult = query.getResultList();<br>        List&lt;T&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        <span class="hljs-keyword">for</span> (Object object : tmpResult) &#123;<br>            result.add(BeanUtil.toBean(object, entityClass));<br>        &#125;<br>        page.setResult(result);<br>        <span class="hljs-keyword">return</span> page;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 统计条数</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">protected</span> Long <span class="hljs-title function_">countSqlResult</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String sql)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">countHql</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;select count(*) from (&quot;</span> + sql + <span class="hljs-string">&quot;) count&quot;</span>;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">valueStr</span> <span class="hljs-operator">=</span> createNativeQuery(countHql).getSingleResult().toString();<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BigDecimal</span>(valueStr.trim()).longValue();<br>        &#125; <span class="hljs-keyword">catch</span> (NoResultException e) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(<span class="hljs-string">&quot;sql can&#x27;t be auto count, sql is:&quot;</span> + countHql, e);<br>        &#125;<br>    &#125;<br><br><br>    <span class="hljs-keyword">private</span> Query <span class="hljs-title function_">createNativeQuery</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String queryString, Object... params)</span> &#123;<br>        Assert.hasText(queryString, <span class="hljs-string">&quot;queryString can not empty&quot;</span>);<br>        Query query;<br>        query = entityManager.createNativeQuery(queryString);<br>        <span class="hljs-keyword">if</span> (params != <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i &lt; params.length; i++) &#123;<br>                query.setParameter(i + <span class="hljs-number">1</span>, params[i]);<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">return</span> query;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 设置分页参数</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">protected</span>  <span class="hljs-keyword">void</span> <span class="hljs-title function_">setPageParameter</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Query q, <span class="hljs-keyword">final</span> Page&lt;T&gt; page)</span> &#123;<br>        q.setFirstResult(page.getOffset());<br>        q.setMaxResults(page.getLimit());<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><ul><li>Page</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate.dao.common;<br><br><span class="hljs-keyword">import</span> org.apache.commons.lang3.StringUtils;<br><br><span class="hljs-keyword">import</span> java.io.Serializable;<br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Page</span>&lt;T&gt; <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">long</span> <span class="hljs-variable">serialVersionUID</span> <span class="hljs-operator">=</span> <span class="hljs-number">1L</span>;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">int</span> limit;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> offset;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">int</span> currentPage;<br><br>    <span class="hljs-keyword">private</span> List&lt;T&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> <span class="hljs-variable">totalCount</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;<br><br>    <span class="hljs-keyword">private</span> String sortField;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> <span class="hljs-variable">totalPage</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Page</span><span class="hljs-params">(Integer page, Integer limit)</span> &#123;<br>        <span class="hljs-built_in">this</span>.currentPage = page - <span class="hljs-number">1</span>;<br>        <span class="hljs-built_in">this</span>.limit = limit;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getOffset</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">if</span> (offset == <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-built_in">this</span>.offset = currentPage * limit;<br>        &#125;<br>        <span class="hljs-keyword">return</span> offset;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getLimit</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> limit;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> List&lt;T&gt; <span class="hljs-title function_">getResult</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setResult</span><span class="hljs-params">(<span class="hljs-keyword">final</span> List&lt;T&gt; result)</span> &#123;<br>        <span class="hljs-built_in">this</span>.result = result;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getTotalCount</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> totalCount;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setTotalCount</span><span class="hljs-params">(<span class="hljs-keyword">final</span> <span class="hljs-type">int</span> totalCount)</span> &#123;<br>        <span class="hljs-built_in">this</span>.totalCount = totalCount;<br>        <span class="hljs-built_in">this</span>.totalPage = <span class="hljs-built_in">this</span>.totalCount / <span class="hljs-built_in">this</span>.limit;<br>        <span class="hljs-keyword">if</span> (totalCount % limit &gt; <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-built_in">this</span>.totalPage++;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getTotalPage</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> totalPage;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setSortField</span><span class="hljs-params">(String sortField)</span> &#123;<br>        <span class="hljs-built_in">this</span>.sortField = sortField;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getOrderString</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">orderString</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span>;<br>        <span class="hljs-keyword">if</span> (StringUtils.isNotBlank(sortField)) &#123;<br>            orderString = <span class="hljs-string">&quot; order by &quot;</span> + sortField;<br>        &#125;<br>        <span class="hljs-keyword">return</span> orderString;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h2 id="业务-UserDao"><a href="#业务-UserDao" class="headerlink" title="业务 UserDao"></a>业务 UserDao</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate.dao;<br><br><span class="hljs-keyword">import</span> com.example.hibernate.dao.common.BaseDaoImpl;<br><span class="hljs-keyword">import</span> com.example.hibernate.entity.User;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Repository;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Repository</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserDao</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">BaseDaoImpl</span>&lt;User&gt; &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">UserDao</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-built_in">super</span>(User.class);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.hibernate;<br><br><span class="hljs-keyword">import</span> com.example.hibernate.dao.UserDao;<br><span class="hljs-keyword">import</span> com.example.hibernate.dao.common.Page;<br><span class="hljs-keyword">import</span> com.example.hibernate.entity.User;<br><span class="hljs-keyword">import</span> org.junit.jupiter.api.Test;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.boot.test.context.SpringBootTest;<br><br><span class="hljs-keyword">import</span> javax.transaction.Transactional;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-meta">@SpringBootTest</span><br><span class="hljs-meta">@Transactional</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">SpringBootHibernateApplicationTests</span> &#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">public</span> UserDao userDao;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">contextLoads</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-type">User</span> <span class="hljs-variable">one</span> <span class="hljs-operator">=</span> userDao.findOne(<span class="hljs-number">1</span>);<br><br>        System.out.println(<span class="hljs-string">&quot;========&quot;</span>);<br>        System.out.println(one);<br>        <span class="hljs-keyword">if</span> (one != <span class="hljs-literal">null</span>) &#123;<br>            userDao.delete(one);<br>        &#125;<br><br>        <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>(<span class="hljs-number">1</span>, <span class="hljs-string">&quot;insert&quot;</span>, <span class="hljs-string">&quot;insert&quot;</span>);<br>        userDao.insert(user);<br>        List&lt;User&gt; all = userDao.findAll();<br><br>        System.out.println(<span class="hljs-string">&quot;========&quot;</span>);<br>        <span class="hljs-keyword">for</span> (User user1 : all) &#123;<br>            System.out.println(user1.toString());<br>        &#125;<br><br>        user.setName(<span class="hljs-string">&quot;update&quot;</span>);<br>        user.setPwd(<span class="hljs-string">&quot;update&quot;</span>);<br>        <span class="hljs-type">User</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> userDao.update(user);<br><br>        System.out.println(<span class="hljs-string">&quot;========&quot;</span>);<br>        System.out.println(update);<br><br>        List&lt;User&gt; nativeQueryList = userDao.getNativeQueryList(<span class="hljs-string">&quot;select * from user&quot;</span>);<br>        System.out.println(<span class="hljs-string">&quot;========&quot;</span>);<br>        System.out.println(nativeQueryList);<br><br>        Page&lt;User&gt; page = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Page</span>&lt;&gt;(<span class="hljs-number">1</span>, <span class="hljs-number">10</span>);<br>        page.setSortField(<span class="hljs-string">&quot;id&quot;</span>);<br>        Page&lt;User&gt; nativeQueryListByPage = userDao.getNativeQueryListByPage(<span class="hljs-string">&quot;select * from user&quot;</span>, page);<br>        System.out.println(<span class="hljs-string">&quot;========&quot;</span>);<br>        System.out.println(nativeQueryListByPage.getResult());<br>        System.out.println(nativeQueryListByPage.getTotalCount());<br>        System.out.println(nativeQueryListByPage.getTotalPage());<br>        System.out.println(nativeQueryListByPage.getOrderString());<br>    &#125;<br><br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出<br><img src="https://www.loquy.cn/images/SpringBootHibernateApplicationTests.jpg"></p><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p><a href="https://github.com/loquy/spring-boot-demo">参见此仓库</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Hibernate是一个开放源代码的对象关系映射框架，它对JDBC进行了非常轻量级的对象封装，它将</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="Hibernate" scheme="http://www.loquy.cn/tags/Hibernate/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot 中使用 MongoDb 上传文件</title>
    <link href="http://www.loquy.cn/posts/e153eef8.html"/>
    <id>http://www.loquy.cn/posts/e153eef8.html</id>
    <published>2022-07-28T01:37:38.000Z</published>
    <updated>2022-07-28T01:37:38.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><h2 id="什么是-MongoDb"><a href="#什么是-MongoDb" class="headerlink" title="什么是 MongoDb"></a>什么是 MongoDb</h2><p>MongoDB 是由C++语言编写的，是一个基于分布式文件存储的开源数据库系统。</p><p>在高负载的情况下，添加更多的节点，可以保证服务器性能。</p><p>MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。</p><p>MongoDB 将数据存储为一个文档，数据结构由键值(key&#x3D;&gt;value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档，数组及文档数组。</p><p><img src="https://www.loquy.cn/images/crud-annotated-document.png"></p><h2 id="MongoDB-GridFS"><a href="#MongoDB-GridFS" class="headerlink" title="MongoDB GridFS"></a>MongoDB GridFS</h2><p>GridFS 用于存储和恢复那些超过16M（BSON文件限制）的文件(如：图片、音频、视频等)。</p><p>GridFS 也是文件存储的一种方式，但是它是存储在MonoDB的集合中。</p><p>GridFS 可以更好的存储大于16M的文件。</p><p>GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k&#x2F;个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。</p><p>GridFS 用两个集合来存储一个文件：fs.files与fs.chunks。</p><p>每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。</p><p>以下是简单的 fs.files 集合文档：</p><figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs clojure">&#123;<br>   <span class="hljs-string">&quot;filename&quot;</span>: <span class="hljs-string">&quot;test.txt&quot;</span><span class="hljs-punctuation">,</span><br>   <span class="hljs-string">&quot;chunkSize&quot;</span>: NumberInt(<span class="hljs-number">261120</span>)<span class="hljs-punctuation">,</span><br>   <span class="hljs-string">&quot;uploadDate&quot;</span>: ISODate(<span class="hljs-string">&quot;2014-04-13T11:32:33.557Z&quot;</span>)<span class="hljs-punctuation">,</span><br>   <span class="hljs-string">&quot;md5&quot;</span>: <span class="hljs-string">&quot;7b762939321e146569b07f72c62cca4f&quot;</span><span class="hljs-punctuation">,</span><br>   <span class="hljs-string">&quot;length&quot;</span>: NumberInt(<span class="hljs-number">646</span>)<br>&#125;<br></code></pre></td></tr></table></figure><p>以下是简单的 fs.chunks 集合文档：</p><figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs clojure">&#123;<br>   <span class="hljs-string">&quot;files_id&quot;</span>: ObjectId(<span class="hljs-string">&quot;534a75d19f54bfec8a2fe44b&quot;</span>)<span class="hljs-punctuation">,</span><br>   <span class="hljs-string">&quot;n&quot;</span>: NumberInt(<span class="hljs-number">0</span>)<span class="hljs-punctuation">,</span><br>   <span class="hljs-string">&quot;data&quot;</span>: <span class="hljs-string">&quot;Mongo Binary Data&quot;</span><br>&#125;<br></code></pre></td></tr></table></figure><h2 id="MongoDB-下载"><a href="#MongoDB-下载" class="headerlink" title="MongoDB 下载"></a>MongoDB 下载</h2><ul><li><a href="https://www.mongodb.com/try/download/community">官网下载页面</a></li><li><a href="https://www.runoob.com/mongodb/mongodb-window-install.html">Windows 平台安装 MongoDB</a></li></ul><h1 id="Maven-项目结构"><a href="#Maven-项目结构" class="headerlink" title="Maven 项目结构"></a>Maven 项目结构</h1><p><img src="https://www.loquy.cn/images/spring-boot-mongodb.jpg"></p><pre><code class="hljs">spring-boot-demo│  .gitignore│  pom.xml│  spring-boot-demo.iml│└─spring-boot-mongodb│  .gitignore│  pom.xml│  spring-boot-mongodb.iml│├─src│  ├─main│  │  ├─java│  │  │  └─com│  │  │      └─example│  │  │          └─mongodb│  │  │              │  SpringBootMongodbApplication.java│  │  │              ││  │  │              ├─controller│  │  │              │      MongoFileController.java│  │  │              ││  │  │              └─utils│  │  │                      MongoFileUtils.java│  │  ││  │  └─resources│  │          application.properties│  ││  └─test│      └─java│          └─com│              └─example│                  └─mongodb│                          SpringBootMongodbApplicationTests.java</code></pre><h1 id="Pom-xml-依赖配置"><a href="#Pom-xml-依赖配置" class="headerlink" title="Pom.xml 依赖配置"></a>Pom.xml 依赖配置</h1><ul><li>spring-boot-demo 项目配置</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.7.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>pom<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modules</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">module</span>&gt;</span>spring-boot-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">module</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">modules</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">optional</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">optional</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">excludes</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">exclude</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">exclude</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">excludes</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br></code></pre></td></tr></table></figure><ul><li>spring-boot-mongodb 子模块配置</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-demo<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>spring-boot-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>spring-boot-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.7.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br><br></code></pre></td></tr></table></figure><h1 id="Application-properties-配置"><a href="#Application-properties-配置" class="headerlink" title="Application.properties 配置"></a>Application.properties 配置</h1><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">server.port</span> = <span class="hljs-string">8088</span><br><span class="hljs-attr">spring.profiles.active</span>=<span class="hljs-string">default</span><br><br><span class="hljs-attr">spring.data.mongodb.uri</span>=<span class="hljs-string">mongodb://localhost:27017/GridFS</span><br><span class="hljs-attr">spring.data.mongodb.database</span>=<span class="hljs-string">GridFS</span><br><span class="hljs-attr">spring.data.mongodb.host</span>=<span class="hljs-string">localhost</span><br><span class="hljs-attr">spring.data.mongodb.port</span>=<span class="hljs-string">27017</span><br><span class="hljs-attr">spring.data.mongodb.username</span>=<span class="hljs-string"></span><br><span class="hljs-attr">spring.data.mongodb.password</span>=<span class="hljs-string"></span><br><br></code></pre></td></tr></table></figure><h1 id="控制器"><a href="#控制器" class="headerlink" title="控制器"></a>控制器</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.mongodb.controller;<br><br><span class="hljs-keyword">import</span> com.example.mongodb.utils.MongoFileUtils;<br><span class="hljs-keyword">import</span> org.springframework.util.StringUtils;<br><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;<br><span class="hljs-keyword">import</span> org.springframework.web.multipart.MultipartFile;<br><br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The type Mongo file controller.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@RestController</span><br><span class="hljs-meta">@RequestMapping(value = &quot;/mongoFile&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MongoFileController</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 上传文件</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> multipartFile the multipart file</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the string</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@PostMapping(&quot;/upload&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">uploadFile</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(&quot;file&quot;)</span> MultipartFile multipartFile)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">originFilename</span> <span class="hljs-operator">=</span> multipartFile.getOriginalFilename();<br>        String fileId;<br>        <span class="hljs-keyword">try</span> &#123;<br>            fileId = MongoFileUtils.uploadFileToGridFs(StringUtils.getFilename(originFilename), multipartFile.getInputStream());<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;上传失败，&quot;</span> + e.getMessage();<br>        &#125;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;上传成功，文件ID：&quot;</span> + fileId;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 删除文件</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> fileId the file id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the string</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@PostMapping(&quot;/remove&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">removeFile</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(&quot;fileId&quot;)</span> String fileId)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            MongoFileUtils.deleteByObjectId(fileId);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;删除失败，&quot;</span> + e.getMessage();<br>        &#125;<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;删除成功&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 显示图片</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> fileId   the file id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> response the response</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@GetMapping(value = &quot;/showImage/&#123;fileId&#125;&quot;)</span><br>    <span class="hljs-keyword">public</span> Object <span class="hljs-title function_">showImage</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable(name = &quot;fileId&quot;)</span> String fileId, HttpServletResponse response)</span>  &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            MongoFileUtils.showImage(fileId, response);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;显示失败，&quot;</span> + e.getMessage();<br>        &#125;<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 下载附件</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> fileId   the file id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> response the response</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@GetMapping(value = &quot;/download/&#123;fileId&#125;&quot;)</span><br>    <span class="hljs-keyword">public</span> Object <span class="hljs-title function_">download</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable(name = &quot;fileId&quot;)</span> String fileId, HttpServletResponse response)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            MongoFileUtils.downloadFile(fileId, response);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;下载失败，&quot;</span> + e.getMessage();<br>        &#125;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;&quot;</span>;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="工具类"><a href="#工具类" class="headerlink" title="工具类"></a>工具类</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.mongodb.utils;<br><br><span class="hljs-keyword">import</span> com.mongodb.client.MongoClient;<br><span class="hljs-keyword">import</span> com.mongodb.client.MongoClients;<br><span class="hljs-keyword">import</span> com.mongodb.client.MongoDatabase;<br><span class="hljs-keyword">import</span> com.mongodb.client.gridfs.GridFSBucket;<br><span class="hljs-keyword">import</span> com.mongodb.client.gridfs.GridFSBuckets;<br><span class="hljs-keyword">import</span> com.mongodb.client.gridfs.GridFSDownloadStream;<br><span class="hljs-keyword">import</span> com.mongodb.client.gridfs.model.GridFSFile;<br><span class="hljs-keyword">import</span> org.bson.types.ObjectId;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Value;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;<br><span class="hljs-keyword">import</span> java.io.InputStream;<br><span class="hljs-keyword">import</span> java.io.OutputStream;<br><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The type Mongo file utils.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MongoFileUtils</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String database;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Sets database.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> database the database</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Value(&quot;$&#123;spring.data.mongodb.database&#125;&quot;)</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setDatabase</span><span class="hljs-params">(String database)</span> &#123;<br>        MongoFileUtils.database = database;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Gets database.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the database</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> MongoDatabase <span class="hljs-title function_">getMongoDatabase</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-type">MongoClient</span> <span class="hljs-variable">mongoClient</span> <span class="hljs-operator">=</span> MongoClients.create();<br>        <span class="hljs-keyword">return</span> mongoClient.getDatabase(database);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Upload file to grid fs string.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> filename the filename</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> in       the in</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the string</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@throws</span> Exception the exception</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">uploadFileToGridFs</span><span class="hljs-params">(String filename, InputStream in)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">GridFSBucket</span> <span class="hljs-variable">bucket</span> <span class="hljs-operator">=</span> GridFSBuckets.create(getMongoDatabase());<br>        <span class="hljs-type">ObjectId</span> <span class="hljs-variable">fileId</span> <span class="hljs-operator">=</span> bucket.uploadFromStream(filename, in);<br>        in.close();<br>        <span class="hljs-keyword">return</span> fileId.toHexString();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Download to stream.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> objectId the object id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> out      the out</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">downloadToStream</span><span class="hljs-params">(String objectId, OutputStream out)</span> &#123;<br>        <span class="hljs-type">GridFSBucket</span> <span class="hljs-variable">bucket</span> <span class="hljs-operator">=</span> GridFSBuckets.create(getMongoDatabase());<br>        bucket.downloadToStream(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectId</span>(objectId), out);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Download file.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> objectId the object id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> response the response</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@throws</span> Exception the exception</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">downloadFile</span><span class="hljs-params">(String objectId, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        OutputStream os;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">outFileName</span> <span class="hljs-operator">=</span> findFileNameById(objectId);<br>        response.setHeader(<span class="hljs-string">&quot;content-disposition&quot;</span>, <span class="hljs-string">&quot;attachment;filename=&quot;</span> + java.net.URLEncoder.encode(outFileName, <span class="hljs-string">&quot;UTF-8&quot;</span>));<br>        os = response.getOutputStream();<br>        downloadToStream(objectId, os);<br>        os.close();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Show image.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> objectId the object id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> response the response</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@throws</span> Exception the exception</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">showImage</span><span class="hljs-params">(String objectId, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        response.setContentType(<span class="hljs-string">&quot;image/jpeg&quot;</span>);<br>        <span class="hljs-type">OutputStream</span> <span class="hljs-variable">out</span> <span class="hljs-operator">=</span> response.getOutputStream();<br>        downloadToStream(objectId, out);<br>        out.flush();<br>        out.close();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Delete by object id.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> objectId the object id</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">deleteByObjectId</span><span class="hljs-params">(String objectId)</span> &#123;<br>        <span class="hljs-type">GridFSBucket</span> <span class="hljs-variable">bucket</span> <span class="hljs-operator">=</span> GridFSBuckets.create(getMongoDatabase());<br>        bucket.delete(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectId</span>(objectId));<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Find file name by id string.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> objectId the object id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the string</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">findFileNameById</span><span class="hljs-params">(String objectId)</span> &#123;<br>        <span class="hljs-type">GridFSBucket</span> <span class="hljs-variable">bucket</span> <span class="hljs-operator">=</span> GridFSBuckets.create(getMongoDatabase());<br>        GridFSDownloadStream stream;<br>        stream = bucket.openDownloadStream(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectId</span>(objectId));<br>        <span class="hljs-type">GridFSFile</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> stream.getGridFSFile();<br>        <span class="hljs-keyword">return</span> file.getFilename();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><h2 id="上传文件"><a href="#上传文件" class="headerlink" title="上传文件"></a>上传文件</h2><p><img src="https://www.loquy.cn/images/mongoFileUpload.jpg"></p><h2 id="下载文件"><a href="#下载文件" class="headerlink" title="下载文件"></a>下载文件</h2><p><img src="https://www.loquy.cn/images/mongoFileDownload.jpg"></p><h2 id="显示图片"><a href="#显示图片" class="headerlink" title="显示图片"></a>显示图片</h2><p><img src="https://www.loquy.cn/images/mongoFileShowImage.jpg"></p><h2 id="删除文件"><a href="#删除文件" class="headerlink" title="删除文件"></a>删除文件</h2><p><img src="https://www.loquy.cn/images/mongoFileRemove.jpg"></p><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p><a href="https://github.com/loquy/spring-boot-demo">参见此仓库</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;h2 id=&quot;什么是-MongoDb&quot;&gt;&lt;a href=&quot;#什么是-MongoDb&quot; class=&quot;headerlink&quot; title=&quot;什么是</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="MongoDb" scheme="http://www.loquy.cn/tags/MongoDb/"/>
    
  </entry>
  
  <entry>
    <title>前后端耦合下实现多文件上传和下拉树选择</title>
    <link href="http://www.loquy.cn/posts/2df684da.html"/>
    <id>http://www.loquy.cn/posts/2df684da.html</id>
    <published>2022-07-23T02:08:59.000Z</published>
    <updated>2022-07-23T02:08:59.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><ul><li>后端框架：SpringBoot</li><li>模板引擎：FreeMarker</li><li>前端框架：JQuery</li><li>前端 UI 组件：Layui、xm-select</li></ul><h1 id="前端代码"><a href="#前端代码" class="headerlink" title="前端代码"></a>前端代码</h1><p>表单部分</p><ul><li>使用 Layui 表单样式。</li><li>编写一个下拉树的分隔区块。</li><li>编写一个上传按钮和上传成功后显示文件名和操作的表格。</li></ul><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;add&quot;</span> <span class="hljs-attr">style</span>=<span class="hljs-string">&quot;height:100%; padding-top:16px;&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-item&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-label&quot;</span>&gt;</span>下拉树：<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">&quot;color:red&quot;</span>&gt;</span>*<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-block&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;selectTree&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-item&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-label&quot;</span>&gt;</span>附件：<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;hidden&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;attachment&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;attachment&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;demo.attachment!&#125;&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-block layui-upload&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;button&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-btn layui-btn-normal&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;testList&quot;</span>&gt;</span>上传文件<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-upload-list&quot;</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-table&quot;</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>文件名<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>操作<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;demoList&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-item&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;button&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;btn layer-cancel&quot;</span>&gt;</span>取消<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">lay-submit</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;btn btn-primary&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;add&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;submitAddForm&quot;</span>&gt;</span>完成<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;reset&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;btn btn-warm&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;resetAddForm&quot;</span>&gt;</span>重置<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span><br></code></pre></td></tr></table></figure><p>JS 部分</p><ul><li>使用 layui.upload 上传组件，上传成功后 js 动态拼接表格元素显示文件名和监听删除操作。</li><li>使用 xm-select 多选组件，初始化使用 ajax 请求接口返回树形数据，然后动态赋值给下拉框。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><code class="hljs javascript">$(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-keyword">var</span> uploadListIns = layui.<span class="hljs-property">upload</span>.<span class="hljs-title function_">render</span>(&#123;<br>        <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#testList&#x27;</span><br>        ,<span class="hljs-attr">elemList</span>: $(<span class="hljs-string">&#x27;#demoList&#x27;</span>)<br>        ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;$&#123;request.contextPath&#125;/file/upload&#x27;</span><br>        ,<span class="hljs-attr">accept</span>: <span class="hljs-string">&#x27;file&#x27;</span><br>        ,<span class="hljs-attr">multiple</span>: <span class="hljs-literal">true</span><br>        ,<span class="hljs-attr">number</span>: <span class="hljs-number">10</span><br>        ,<span class="hljs-attr">auto</span>: <span class="hljs-literal">true</span><br>        ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res, index, upload</span>)&#123; <span class="hljs-comment">//成功的回调</span><br>            <span class="hljs-keyword">var</span> attachment = $(<span class="hljs-string">&quot;#attachment&quot;</span>).<span class="hljs-title function_">val</span>();<br>            <span class="hljs-keyword">var</span> attachmentArray = attachment ? attachment.<span class="hljs-title function_">split</span>(<span class="hljs-string">&quot;,&quot;</span>) : [];<br>            attachmentArray.<span class="hljs-title function_">push</span>(res.<span class="hljs-property">uuid</span>)<br>            $(<span class="hljs-string">&quot;#attachment&quot;</span>).<span class="hljs-title function_">val</span>(attachmentArray.<span class="hljs-title function_">join</span>(<span class="hljs-string">&quot;,&quot;</span>))<br>            <span class="hljs-title function_">appendTr</span>(res.<span class="hljs-property">uuid</span>, res.<span class="hljs-property">fileName</span>, res.<span class="hljs-property">fileId</span>);<br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br>        ,<span class="hljs-attr">error</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>        &#125;<br>    &#125;);<br><br>    &lt;#list files <span class="hljs-keyword">as</span> file&gt;<br>        <span class="hljs-title function_">appendTr</span>(<span class="hljs-string">&#x27;$&#123;file.uuid&#125;&#x27;</span>, <span class="hljs-string">&#x27;$&#123;file.fileName&#125;&#x27;</span>, <span class="hljs-string">&#x27;$&#123;file.fileId&#125;&#x27;</span>)<br>    &lt;/#list&gt;<br><br>    <span class="hljs-keyword">function</span> <span class="hljs-title function_">appendTr</span>(<span class="hljs-params">uuid, fileName, fileId</span>) &#123;<br>        <span class="hljs-keyword">let</span> downloadUrl = <span class="hljs-string">&#x27;$&#123;request.contextPath&#125;/file/download?fileId=&#x27;</span> + fileId<br>        <span class="hljs-keyword">var</span> tr = $([<span class="hljs-string">&#x27;&lt;tr id=&quot;&#x27;</span>+ uuid +<span class="hljs-string">&#x27;&quot;&gt;&#x27;</span><br>                    ,<span class="hljs-string">&#x27;&lt;td&gt;&#x27;</span>+ <span class="hljs-string">&#x27;&lt;a href=&quot;&#x27;</span> + downloadUrl + <span class="hljs-string">&#x27;&quot; style=&quot;color:blue; text-decoration:underline;&quot;&gt;&#x27;</span> + fileName + <span class="hljs-string">&#x27;&lt;/a&gt;&#x27;</span> +<span class="hljs-string">&#x27;&lt;/td&gt;&#x27;</span><br>                    ,<span class="hljs-string">&#x27;&lt;td&gt;&#x27;</span><br>                    ,<span class="hljs-string">&#x27;&lt;button class=&quot;layui-btn layui-btn-xs layui-btn-danger demo-delete&quot;&gt;删除&lt;/button&gt;&#x27;</span><br>                    ,<span class="hljs-string">&#x27;&lt;/td&gt;&#x27;</span><br>                    ,<span class="hljs-string">&#x27;&lt;/tr&gt;&#x27;</span>].<span class="hljs-title function_">join</span>(<span class="hljs-string">&#x27;&#x27;</span>));<br><br>        tr.<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;.demo-delete&#x27;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;click&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>            <span class="hljs-comment">// Ajax 模拟 Form 表单提交</span><br>            <span class="hljs-keyword">var</span> formData = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FormData</span>();<br>            formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&quot;uuid&quot;</span>, tr.<span class="hljs-title function_">attr</span>(<span class="hljs-string">&#x27;id&#x27;</span>));<br>            $.<span class="hljs-title function_">ajax</span>(&#123;<br>                <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;post&quot;</span>,<br>                <span class="hljs-attr">async</span>: <span class="hljs-literal">false</span>,<br>                <span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;$&#123;request.contextPath&#125;/file/remove&#x27;</span>,<br>                <span class="hljs-attr">dataType</span>: <span class="hljs-string">&quot;json&quot;</span>,<br>                <span class="hljs-attr">data</span>: formData,<br>                <span class="hljs-attr">contentType</span>: <span class="hljs-literal">false</span>,<span class="hljs-comment">//这里</span><br>                <span class="hljs-attr">processData</span>: <span class="hljs-literal">false</span>,<span class="hljs-comment">//这两个一定设置为false</span><br>                <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">res</span>) &#123;<br>                    <span class="hljs-title class_">Array</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">removeByValue</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) &#123;<br>                        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-variable language_">this</span>.<span class="hljs-property">length</span>; i++) &#123;<br>                            <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>[i] === val) &#123;<br>                                <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">splice</span>(i, <span class="hljs-number">1</span>);<br>                                i--;<br>                            &#125;<br>                        &#125;<br>                        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>;<br>                    &#125;<br>                    <span class="hljs-keyword">var</span> attachment = $(<span class="hljs-string">&quot;#attachment&quot;</span>).<span class="hljs-title function_">val</span>();<br>                    <span class="hljs-keyword">var</span> attachmentArray = attachment ? attachment.<span class="hljs-title function_">split</span>(<span class="hljs-string">&quot;,&quot;</span>) : [];<br>                    attachmentArray.<span class="hljs-title function_">removeByValue</span>(tr.<span class="hljs-title function_">attr</span>(<span class="hljs-string">&#x27;id&#x27;</span>));<br>                    $(<span class="hljs-string">&quot;#attachment&quot;</span>).<span class="hljs-title function_">val</span>(attachmentArray.<span class="hljs-title function_">join</span>(<span class="hljs-string">&quot;,&quot;</span>))<br>                &#125;,<br>                <span class="hljs-attr">error</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) &#123;<br>                    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(err)<br>                &#125;<br>            &#125;);<br>            tr.<span class="hljs-title function_">remove</span>();<br>        &#125;);<br><br>        $(<span class="hljs-string">&#x27;#demoList&#x27;</span>).<span class="hljs-title function_">append</span>(tr);<br>    &#125;<br>    <br>    <span class="hljs-keyword">var</span> selectTreeXmSelect = layui.<span class="hljs-property">xmSelect</span>.<span class="hljs-title function_">render</span>(&#123;<br>        <span class="hljs-attr">el</span>: <span class="hljs-string">&#x27;#selectTree&#x27;</span>,<br>        <span class="hljs-attr">autoRow</span>: <span class="hljs-literal">true</span>,<br>        <span class="hljs-attr">name</span>: <span class="hljs-string">&quot;selectTree&quot;</span>,<br>        <span class="hljs-comment">//单选模式</span><br>        <span class="hljs-attr">radio</span>: <span class="hljs-literal">true</span>,<br>        <span class="hljs-attr">height</span>: <span class="hljs-string">&#x27;auto&#x27;</span>,<br>        <span class="hljs-attr">data</span>: []<br>    &#125;)<br>    <br>    $.<span class="hljs-title function_">ajax</span>(&#123;<br>        <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;get&quot;</span>,<br>        <span class="hljs-attr">async</span>: <span class="hljs-literal">false</span>,<br>        <span class="hljs-attr">url</span>: <span class="hljs-title class_">Ams</span>.<span class="hljs-property">ctxPath</span> + <span class="hljs-string">&quot;/demo/demo/selectTree&quot;</span>,<br>        <span class="hljs-attr">dataType</span>: <span class="hljs-string">&quot;json&quot;</span>,<br>        <span class="hljs-attr">data</span>: &#123;&#125;,<br>        <span class="hljs-attr">contentType</span>: <span class="hljs-string">&quot;application/json;charset=UTF-8&quot;</span>,<br>        <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>) &#123;<br>            selectTreeXmSelect.<span class="hljs-title function_">update</span>(&#123;<br>                <span class="hljs-attr">data</span>: res,<br>                <span class="hljs-attr">tree</span>: &#123;<br>                    <span class="hljs-attr">show</span>: <span class="hljs-literal">true</span>,<br>                    <span class="hljs-comment">//非严格模式</span><br>                    <span class="hljs-attr">strict</span>: <span class="hljs-literal">false</span>,<br>                    <span class="hljs-comment">//展开所有节点</span><br>                    <span class="hljs-attr">expandedKeys</span>: <span class="hljs-literal">true</span>,<br>                &#125;,<br>            &#125;)<br>            selectTreeXmSelect.<span class="hljs-title function_">setValue</span>([<span class="hljs-string">&#x27;$&#123;demo.selectTree!&#125;&#x27;</span>])<br>        &#125;,<br>        <span class="hljs-attr">error</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">err</span>) &#123;<br>            <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(err)<br>        &#125;<br>    &#125;)<br>&#125;);<br></code></pre></td></tr></table></figure><h1 id="后端代码"><a href="#后端代码" class="headerlink" title="后端代码"></a>后端代码</h1><p>控制器</p><ul><li>页面跳转和获取下拉树数据的接口。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 跳转页面</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@RequestMapping(value = &quot;/editDemo&quot;, method = RequestMethod.GET)</span><br><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title function_">editDemo</span><span class="hljs-params">(ModelAndView modelAndView, String id)</span> &#123;<br>    <span class="hljs-type">Demo</span> <span class="hljs-variable">demo</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Demo</span>();<br>    <span class="hljs-keyword">if</span> (StringUtils.isNotEmpty(id)) &#123;<br>        demo = demoService.getById(id);<br>    &#125;<br>    List&lt;Object&gt; files = demoService.getFiles(demo);<br>    modelAndView.addObject(<span class="hljs-string">&quot;files&quot;</span>, files);<br>    modelAndView.addObject(<span class="hljs-string">&quot;demo&quot;</span>, demo);<br>    modelAndView.setViewName(<span class="hljs-string">&quot;/demo/demoEdit&quot;</span>);<br>    <span class="hljs-keyword">return</span> modelAndView;<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 下拉树</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@RequestMapping(value = &quot;/selectTree&quot;, method = RequestMethod.GET)</span><br><span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">selectTree</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> demoService.selectTree();<br>&#125;<br></code></pre></td></tr></table></figure><p>Service</p><ul><li>构造树形数据以及查询文件信息。</li><li>文件上传、删除、下载相关操作的接口，单独抽出一个模块来实现，实现方式有很多种，例如可存储到本地，也可以存储到 MongoDB 等，具体实现以后单独写篇文章。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">selectTree</span><span class="hljs-params">()</span> &#123;<br>    List&lt;SelectTree&gt; selectTree = selectTreeService.list();<br>    <span class="hljs-keyword">return</span> menuList(selectTree);<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Menu list list.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> menu the menu</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">menuList</span><span class="hljs-params">(List&lt;SelectTree&gt; menu)</span> &#123;<br>    List&lt;Object&gt; list = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>    <span class="hljs-keyword">for</span> (SelectTree selectTree : menu) &#123;<br>        Map&lt;String, Object&gt; map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">LinkedHashMap</span>&lt;&gt;();<br>        <span class="hljs-keyword">if</span> (selectTree.getParentId() == <span class="hljs-literal">null</span>) &#123;<br>            menuItem(menu, list, selectTree, map);<br>        &#125;<br>    &#125;<br>    <span class="hljs-keyword">return</span> list;<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Menu child list.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> menu the menu</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> id   the id</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">menuChild</span><span class="hljs-params">(List&lt;SelectTree&gt; menu, String id)</span> &#123;<br>    List&lt;Object&gt; list = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>    <span class="hljs-keyword">for</span> (SelectTree selectTree : menu) &#123;<br>        Map&lt;String, Object&gt; map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">LinkedHashMap</span>&lt;&gt;();<br>        <span class="hljs-keyword">if</span> (selectTree.getParentId() != <span class="hljs-literal">null</span> &amp;&amp; selectTree.getParentId().equals(id)) &#123;<br>            menuItem(menu, list, selectTree, map);<br>        &#125;<br>    &#125;<br>    <span class="hljs-keyword">return</span> list;<br>&#125;<br><br><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">menuItem</span><span class="hljs-params">(</span><br><span class="hljs-params">        List&lt;SelectTree&gt; menu,</span><br><span class="hljs-params">        List&lt;Object&gt; list,</span><br><span class="hljs-params">        SelectTree selectTree,</span><br><span class="hljs-params">        Map&lt;String, Object&gt; map</span><br><span class="hljs-params">)</span> &#123;<br>    map.put(<span class="hljs-string">&quot;value&quot;</span>, selectTree.getUuid());<br>    map.put(<span class="hljs-string">&quot;name&quot;</span>, selectTree.getPointName());<br>    map.put(<span class="hljs-string">&quot;pid&quot;</span>, selectTree.getParentId());<br>    List&lt;Object&gt; children = menuChild(menu, selectTree.getUuid());<br>    map.put(<span class="hljs-string">&quot;children&quot;</span>, children);<br>    list.add(map);<br>&#125;<br><br><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">getFiles</span><span class="hljs-params">(Demo demo)</span> &#123;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">attachment</span> <span class="hljs-operator">=</span> demo.getAttachment();<br>    <span class="hljs-keyword">if</span> (StringUtils.isEmpty(attachment)) &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>    &#125;<br>    String[] attachmentArray = attachment.split(<span class="hljs-string">&quot;,&quot;</span>);<br>    <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">in</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();<br>    <span class="hljs-keyword">for</span> (String s : attachmentArray) &#123;<br>        <span class="hljs-keyword">if</span> (in.length() == <span class="hljs-number">0</span>) &#123;<br>            in.append(<span class="hljs-string">&quot;&#x27;&quot;</span>).append(s).append(<span class="hljs-string">&quot;&#x27;&quot;</span>);<br>        &#125;<br>        in.append(<span class="hljs-string">&quot;,&#x27;&quot;</span>).append(s).append(<span class="hljs-string">&quot;&#x27;&quot;</span>);<br>    &#125;<br>    <span class="hljs-keyword">return</span> demoDao.getNativeQueryList(filesSql(in.toString()));<br>&#125;<br><br><span class="hljs-keyword">public</span> String <span class="hljs-title function_">filesSql</span><span class="hljs-params">(String in)</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;SELECT\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tuuid,\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tfile_name,\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tfile_id \n&quot;</span> +<br>            <span class="hljs-string">&quot;FROM\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tFILE \n&quot;</span> +<br>            <span class="hljs-string">&quot;WHERE\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tuuid IN (&quot;</span> + in + <span class="hljs-string">&quot;)&quot;</span>;<br>&#125;<br></code></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;环境&quot;&gt;&lt;a href=&quot;#环境&quot; class=&quot;headerlink&quot; title=&quot;环境&quot;&gt;&lt;/a&gt;环境&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;后端框架：SpringBoot&lt;/li&gt;
&lt;li&gt;模板引擎：FreeMarker&lt;/li&gt;
&lt;li&gt;前端框架：JQuery&lt;/l</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/JavaScript/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="FreeMarker" scheme="http://www.loquy.cn/tags/FreeMarker/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/tags/JavaScript/"/>
    
    <category term="JQuery" scheme="http://www.loquy.cn/tags/JQuery/"/>
    
    <category term="Layui" scheme="http://www.loquy.cn/tags/Layui/"/>
    
  </entry>
  
  <entry>
    <title>Oracle 常用查询语句总结</title>
    <link href="http://www.loquy.cn/posts/e95076da.html"/>
    <id>http://www.loquy.cn/posts/e95076da.html</id>
    <published>2022-07-06T08:27:48.000Z</published>
    <updated>2022-07-06T08:27:48.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ROWNUM-字段"><a href="#ROWNUM-字段" class="headerlink" title="ROWNUM 字段"></a>ROWNUM 字段</h1><p>rownum 是 Oracle 系统顺序分配为从查询返回的行的编号，返回的第一行分配的是 1，返回的第二行分配的是 2，这个伪字段可以用于限制返回查询的总行数，且 rownum 不可以以任何表的名称作为前缀。</p><ol><li>rownum 对于等于某值的查询条件：如果想找到第一条查询数据，可以使用 rownum &#x3D; 1 作为查询条件，但是想找到第二条查询数据，使用 rownum &#x3D; 2 则查不到数据，原因是：rownum 都是从 1开始，但是 1 以上的自然数与 rownum 做等于时，都认为是 false 条件，所以无法查询到 rownum &#x3D; n（ n &gt; 1 的自然数）；</li><li>rownum 对于大于某值的查询条件：要是想查询出第二行以后的记录，直接使用 rownum &gt; 2 是查不出数据的，原因是 rownum 是一个总是以 1 开始的伪列，rownum &gt; n（ n &gt; 1 的自然数）依然不成立。可以使用子查询来解决，注意子查询中的 rownum 必须要有别名，否则还是不会查出记录来，这是因为 rownum 不是某个表的列，如果不起别名的话，无法知道 rownum 是子查询的列还是主查询的列。</li></ol><h1 id="DUAL-表"><a href="#DUAL-表" class="headerlink" title="DUAL 表"></a>DUAL 表</h1><p>Oracle 提供的最小的工作表，只有一行一列，具有某些特殊功用。</p><h2 id="表结构"><a href="#表结构" class="headerlink" title="表结构"></a>表结构</h2><table><thead><tr><th>Name</th><th>Type</th></tr></thead><tbody><tr><td>DUMMY</td><td>Varchar(1)</td></tr></tbody></table><h2 id="特性"><a href="#特性" class="headerlink" title="特性"></a>特性</h2><ol><li>Oracle 提供的最小的表，不论进行何种操作（不要删除记录），它都只有一条记录——‘X’。例如：执行 select * from dual，里面只有一条记录；执行 insert into dual values(‘Y’)后，再次查询 dual表，仍然显示一条记录。</li><li>是 sys 用户下的一张内部表，所有用户都可以使用 DUAL 名称访问，无论什么时候这个表总是存在。例如：执行一个查看当前日期的语句 select sysdate from dual，这条语句在放在放在任何一个 oracle 数据库当中都不会报错，所以一般做一些特定查询的时候用这个表是最稳妥的。</li></ol><h2 id="用途"><a href="#用途" class="headerlink" title="用途"></a>用途</h2><ol><li>select 计算常量表达式、伪列等值 oracle 内部处理使它只返回一行数据，而使用其它表时可能返回多个数据行。</li><li>查看当前用户 select user from dual;select count(*) from dual;</li><li>用做计算器 select 7<em>9</em>10-10 from dual；</li><li>调用系统函数<ul><li>获得当前系统时间 select to_char(sysdate,’yyyy-mm-dd hh24:mi:ss’) from dual;</li><li>获得主机名 select sys_context(‘userenv’,’terminal’) from dual;</li><li>获得当前 locale select sys_context(‘userenv’,’language’) from dual;</li><li>获得一个随机数 select DBMS_RANDOM.random from dual;</li></ul></li><li>查看序列值<ul><li>创建序列 aaa 以1开始，每次加1 create sequence aaa increment by 1 start with 1;</li><li>获得序列 aaa 的下一个序列值 select aaa.nextval from dual;</li><li>获得序列 aaa 的当前序列值 select aaa.currval from dual;</li></ul></li></ol><h1 id="UNION-与-UNION-ALL-的区别"><a href="#UNION-与-UNION-ALL-的区别" class="headerlink" title="UNION 与 UNION ALL 的区别"></a>UNION 与 UNION ALL 的区别</h1><ol><li>UNION：对两个结果集进行并集操作，不包括重复行，同时进行默认规则的排序。</li><li>UNION ALL：对两个结果集进行并集操作，包括重复行，不进行排序。</li></ol><h1 id="查询最新的一条数据"><a href="#查询最新的一条数据" class="headerlink" title="查询最新的一条数据"></a>查询最新的一条数据</h1><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span><br><span class="hljs-operator">*</span> <br><span class="hljs-keyword">FROM</span><br>( <span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> BOOK <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> CREATE_DATE <span class="hljs-keyword">DESC</span> ) <br><span class="hljs-keyword">WHERE</span><br>ROWNUM <span class="hljs-operator">=</span> <span class="hljs-number">1</span><br></code></pre></td></tr></table></figure><h1 id="保留-N-位小数"><a href="#保留-N-位小数" class="headerlink" title="保留 N 位小数"></a>保留 N 位小数</h1><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- round(m,n)，四舍五入，0.87。</span><br><span class="hljs-keyword">SELECT</span><br>ROUND( <span class="hljs-number">0.866</span>, <span class="hljs-number">2</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- trunc(m,n)，不四舍五入，0.86。</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( <span class="hljs-number">0.866</span>, <span class="hljs-number">2</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br></code></pre></td></tr></table></figure><h1 id="查询当天时间"><a href="#查询当天时间" class="headerlink" title="查询当天时间"></a>查询当天时间</h1><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- 使用 trunc 函数截断时间</span><br><span class="hljs-comment">-- 2022-07-06 00:00:00，今天的日期</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-07-01 00:00:00，返回当月第一天.</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;mm&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-01-01 00:00:00，返回当年第一天</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;yy&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-07-06 00:00:00，返回当前年月日</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;dd&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-01-01 00:00:00，返回当年第一天</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;yyyy&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-07-03 00:00:00，返回当前星期的第一天</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;d&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-07-06 10:00:00，当前时间</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;hh&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br><span class="hljs-comment">-- 2022-07-06 10:51:00，RUNC()函数没有秒的精</span><br><span class="hljs-keyword">SELECT</span><br>TRUNC( SYSDATE, <span class="hljs-string">&#x27;mi&#x27;</span> ) <br><span class="hljs-keyword">FROM</span><br>DUAL;<br></code></pre></td></tr></table></figure><h1 id="补空行"><a href="#补空行" class="headerlink" title="补空行"></a>补空行</h1><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span><br><span class="hljs-operator">*</span> <br><span class="hljs-keyword">FROM</span><br>( <span class="hljs-keyword">SELECT</span> id, name <span class="hljs-keyword">FROM</span> BOOK <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span> <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">NULL</span> id, <span class="hljs-string">&#x27;book&#x27;</span> name <span class="hljs-keyword">FROM</span> DUAL <span class="hljs-keyword">CONNECT</span> <span class="hljs-keyword">BY</span> ROWNUM <span class="hljs-operator">&lt;</span> <span class="hljs-number">11</span> ) <br><span class="hljs-keyword">WHERE</span><br>ROWNUM <span class="hljs-operator">&lt;</span> <span class="hljs-number">11</span><br></code></pre></td></tr></table></figure><h1 id="分页查询"><a href="#分页查询" class="headerlink" title="分页查询"></a>分页查询</h1><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- where 条件：rn &gt; (page - 1) * pageSize and rn &lt;= (page) * pageSize</span><br><span class="hljs-keyword">SELECT</span><br><span class="hljs-operator">*</span> <br><span class="hljs-keyword">FROM</span><br>( <span class="hljs-keyword">SELECT</span> t.<span class="hljs-operator">*</span>, ROWNUM rn <span class="hljs-keyword">FROM</span> BOOK t ) <br><span class="hljs-keyword">WHERE</span><br>rn <span class="hljs-operator">&gt;</span> ( <span class="hljs-number">1</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span> ) <span class="hljs-operator">*</span> <span class="hljs-number">10</span> <br><span class="hljs-keyword">AND</span> rn <span class="hljs-operator">&lt;=</span> ( <span class="hljs-number">1</span> ) <span class="hljs-operator">*</span> <span class="hljs-number">10</span><br></code></pre></td></tr></table></figure><h1 id="TO-CHAR-和-TO-DATE-日期转换"><a href="#TO-CHAR-和-TO-DATE-日期转换" class="headerlink" title="TO_CHAR 和 TO_DATE 日期转换"></a>TO_CHAR 和 TO_DATE 日期转换</h1><h2 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h2><p>TO_DATE(‘字符串’, ‘格式’)<br>TO_CHAR(‘日期’, ‘格式’)</p><h2 id="含义"><a href="#含义" class="headerlink" title="含义"></a>含义</h2><p>TO_DATE：将字符串转化为日期型。<br>TO_CHAR：将日期或数字转换为 char 数据类型。</p><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;2022-7-06&#x27;</span>,<span class="hljs-string">&#x27;yyyy-mm-dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;2022-7-06&#x27;</span>,<span class="hljs-string">&#x27;yyyy.mm.dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;2022-7-06&#x27;</span>,<span class="hljs-string">&#x27;yyyy/mm/dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;2022-7-06&#x27;</span>,<span class="hljs-string">&#x27;yyyy-mm-dd hh24:mi:ss&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;2022.7.06&#x27;</span>,<span class="hljs-string">&#x27;yyyy-mm-dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;2022/7/06&#x27;</span>,<span class="hljs-string">&#x27;yyyy-mm-dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_DATE(<span class="hljs-string">&#x27;20220706&#x27;</span>,<span class="hljs-string">&#x27;yyyy-mm-dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 00:00:00</span><br><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;yyyy-mm-dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;yyyy/mm/dd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022/07/06</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;yyyymmdd&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 20220706</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;yyyy-mm-dd hh24:mi:ss&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022-07-06 16:14:34</span><br><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;yyyy&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 2022</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;mm&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 07</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;hh24&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 16</span><br><span class="hljs-keyword">SELECT</span> SYSDATE, TO_CHAR(SYSDATE,<span class="hljs-string">&#x27;mi&#x27;</span>) <span class="hljs-keyword">FROM</span> DUAL; <span class="hljs-comment">-- 14</span><br></code></pre></td></tr></table></figure><h1 id="DECODE-条件取值"><a href="#DECODE-条件取值" class="headerlink" title="DECODE 条件取值"></a>DECODE 条件取值</h1><h2 id="语法-1"><a href="#语法-1" class="headerlink" title="语法"></a>语法</h2><p>decode(条件, 值1, 翻译值1, 值2, 翻译值2, …, 值n, 翻译值n, 缺省值)</p><h2 id="含义-1"><a href="#含义-1" class="headerlink" title="含义"></a>含义</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs sql">IF 条件<span class="hljs-operator">=</span>值<span class="hljs-number">1</span> <span class="hljs-keyword">THEN</span><br><span class="hljs-keyword">RETURN</span>(翻译值<span class="hljs-number">1</span>)<br>ELSIF 条件<span class="hljs-operator">=</span>值<span class="hljs-number">2</span> <span class="hljs-keyword">THEN</span><br><span class="hljs-keyword">RETURN</span>(翻译值<span class="hljs-number">2</span>)<br>......<br>ELSIF 条件<span class="hljs-operator">=</span>值n <span class="hljs-keyword">THEN</span><br><span class="hljs-keyword">RETURN</span>(翻译值n)　　<br><span class="hljs-keyword">ELSE</span><br><span class="hljs-keyword">RETURN</span>(缺省值)<br><span class="hljs-keyword">END</span> IF　　<br></code></pre></td></tr></table></figure><h1 id="NVL-和-NVL2-为空值赋值"><a href="#NVL-和-NVL2-为空值赋值" class="headerlink" title="NVL 和 NVL2 为空值赋值"></a>NVL 和 NVL2 为空值赋值</h1><h2 id="NVL"><a href="#NVL" class="headerlink" title="NVL"></a>NVL</h2><h3 id="语法-2"><a href="#语法-2" class="headerlink" title="语法"></a>语法</h3><p>NVL (expr1, expr2)</p><h3 id="含义-2"><a href="#含义-2" class="headerlink" title="含义"></a>含义</h3><p>若 expr1 为NULL，返回 expr2；expr1不为 NULL，返回 expr1。<br>注意两者的类型要一致。</p><h2 id="NVL2"><a href="#NVL2" class="headerlink" title="NVL2"></a>NVL2</h2><h3 id="语法-3"><a href="#语法-3" class="headerlink" title="语法"></a>语法</h3><p>NVL2 (expr1, expr2, expr3)</p><h3 id="含义-3"><a href="#含义-3" class="headerlink" title="含义"></a>含义</h3><p>expr1 不为 NULL，返回 expr2；expr2 为 NULL，返回 expr3。<br>expr2 和 expr3 类型不同的话，expr3 会转换为 expr2 的类型。</p><h1 id="CONNECT-BY-LEVEL-递归查询"><a href="#CONNECT-BY-LEVEL-递归查询" class="headerlink" title="CONNECT BY LEVEL 递归查询"></a>CONNECT BY LEVEL 递归查询</h1><h2 id="构造连续的数字"><a href="#构造连续的数字" class="headerlink" title="构造连续的数字"></a>构造连续的数字</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> LEVEL <br><span class="hljs-keyword">FROM</span><br>DUAL <span class="hljs-keyword">CONNECT</span> <span class="hljs-keyword">BY</span> LEVEL <span class="hljs-operator">&lt;=</span> <span class="hljs-number">5</span>;<br></code></pre></td></tr></table></figure><h2 id="构造连续的日期"><a href="#构造连续的日期" class="headerlink" title="构造连续的日期"></a>构造连续的日期</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> SYSDATE<br><span class="hljs-operator">+</span> LEVEL <br><span class="hljs-keyword">FROM</span><br>DUAL <span class="hljs-keyword">CONNECT</span> <span class="hljs-keyword">BY</span> LEVEL <span class="hljs-operator">&lt;=</span> <span class="hljs-number">5</span>;<br></code></pre></td></tr></table></figure><h2 id="按逗号分隔字符串"><a href="#按逗号分隔字符串" class="headerlink" title="按逗号分隔字符串"></a>按逗号分隔字符串</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span><br>REGEXP_SUBSTR( <span class="hljs-string">&#x27;a,b,c&#x27;</span>, <span class="hljs-string">&#x27;[^,]+&#x27;</span>, <span class="hljs-number">1</span>, LEVEL ) <br><span class="hljs-keyword">FROM</span><br>DUAL <span class="hljs-keyword">CONNECT</span> <span class="hljs-keyword">BY</span> REGEXP_SUBSTR( <span class="hljs-string">&#x27;a,b,c&#x27;</span>, <span class="hljs-string">&#x27;[^,]+&#x27;</span>, <span class="hljs-number">1</span>, LEVEL ) <span class="hljs-keyword">IS</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span><br></code></pre></td></tr></table></figure><p>原理说明：</p><ol><li>dual 只有 1 条记录，所以构造树时，每层都只有 1 个记录，可能形成了包含本记录的 n 次不同  level 的重复。</li><li>connect by 条件：按层级截取表达不能为空，因为只有 3 个元素，所以只到 3 级。</li><li>正则表达式的含义：<br>pattern &#x3D;<code>&#39;[^,]+&#39;，[]</code>表示待选集合，但以 ^ 开头，表示非逗号的所有元素。<br>是从左开始截取、直到遇到不符合 pattern 的元素。</li></ol>]]></content>
    
    
    <summary type="html">整理记录常用 Oracle 常用查询语句，以此备忘，持续更新中...</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Oracle" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Oracle/"/>
    
    
    <category term="SQL" scheme="http://www.loquy.cn/tags/SQL/"/>
    
    <category term="Oracle" scheme="http://www.loquy.cn/tags/Oracle/"/>
    
  </entry>
  
  <entry>
    <title>前后端耦合下实现多级联动选择下拉框</title>
    <link href="http://www.loquy.cn/posts/9c06e8ab.html"/>
    <id>http://www.loquy.cn/posts/9c06e8ab.html</id>
    <published>2022-06-29T05:48:42.000Z</published>
    <updated>2022-06-29T05:48:42.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><ul><li>后端框架：SpringBoot</li><li>模板引擎：FreeMarker</li><li>前端框架：JQuery</li><li>前端 UI 组件：Layui</li></ul><h1 id="前端代码"><a href="#前端代码" class="headerlink" title="前端代码"></a>前端代码</h1><ul><li>容器中设定 class&#x3D;”layui-form” 来标识一个 Layui 表单元素块。</li><li>放多个下拉框，第一个下拉框需要通过模板引擎循环渲染变量。</li><li>lay-filter：过滤器，主要用于事件匹配。</li></ul><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form custom-form&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-item&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-label&quot;</span>&gt;</span>所属区域：<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-inline&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;province&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;province&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;province&quot;</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">selected</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;&quot;</span>&gt;</span>请选择省<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>                &lt;#list province! as item&gt;<br>                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;item.uuid&#125;&quot;</span> &gt;</span>$&#123;item.name&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>                &lt;/#list&gt;<br>            <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-inline&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;city&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;city&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;city&quot;</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">selected</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;&quot;</span>&gt;</span>请选择市<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-inline&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;county&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;county&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;county&quot;</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">selected</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;&quot;</span>&gt;</span>请选择县<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-inline&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;town&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;town&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;town&quot;</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">selected</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;&quot;</span>&gt;</span>请选择镇<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-inline&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;village&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;village&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;village&quot;</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">selected</span>=<span class="hljs-string">&quot;selected&quot;</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">&quot;disabled&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;&quot;</span> &gt;</span>请选择村<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span><br></code></pre></td></tr></table></figure><ul><li>使用 layui.form.on 监听事件，下拉选择框选中时触发事件，通过 ajax 请求下级的数据。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><code class="hljs javascript">$(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>    layui.<span class="hljs-title function_">use</span>([<span class="hljs-string">&#x27;jquery&#x27;</span>, <span class="hljs-string">&#x27;form&#x27;</span>], <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>        <span class="hljs-keyword">let</span> form = layui.<span class="hljs-property">form</span>;<br>        form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(province)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) &#123;<br>            <span class="hljs-title function_">selectRegion</span>(<span class="hljs-string">&quot;#province&quot;</span>, [<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#city&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择市&quot;</span>&#125;,<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#county&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择县&quot;</span>&#125;,<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#town&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择镇&quot;</span>&#125;,<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#village&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择村&quot;</span>&#125;,<br>            ], data, form);<br>        &#125;);<br>        form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(city)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) &#123;<br>            <span class="hljs-title function_">selectRegion</span>(<span class="hljs-string">&quot;#city&quot;</span>, [<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#county&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择县&quot;</span>&#125;,<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#town&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择镇&quot;</span>&#125;,<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#village&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择村&quot;</span>&#125;,<br>            ], data, form);<br>        &#125;);<br>        form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(county)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) &#123;<br>            <span class="hljs-title function_">selectRegion</span>(<span class="hljs-string">&quot;#county&quot;</span>, [<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#town&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择镇&quot;</span>&#125;,<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#village&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择村&quot;</span>&#125;,<br>            ], data, form);<br>        &#125;);<br>        form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(town)&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) &#123;<br>            <span class="hljs-title function_">selectRegion</span>(<span class="hljs-string">&quot;#town&quot;</span>, [<br>                &#123;<span class="hljs-attr">element</span>: <span class="hljs-string">&quot;#village&quot;</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">&quot;请选择村&quot;</span>&#125;,<br>            ], data, form)<br>        &#125;);<br>    &#125;);<br>&#125;);<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">selectRegion</span>(<span class="hljs-params">element, childElements, data, form</span>) &#123;<br>    <span class="hljs-keyword">let</span> regionId = data.<span class="hljs-property">value</span>;<br>    $.<span class="hljs-title function_">ajax</span>(&#123;<br>        <span class="hljs-attr">url</span>: <span class="hljs-string">&quot;$&#123;request.contextPath&#125;/select&quot;</span>,<br>        <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;get&quot;</span>,<br>        <span class="hljs-attr">dataType</span>: <span class="hljs-string">&quot;json&quot;</span>,<br>        <span class="hljs-attr">data</span>: &#123;<br>            <span class="hljs-string">&quot;regionId&quot;</span>: regionId<br>        &#125;,<br>        <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) &#123;<br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; childElements.<span class="hljs-property">length</span>; i++) &#123;<br>                &lt;!--清空下拉框中的缓存--&gt;<br>                $(childElements[i].<span class="hljs-property">element</span>).<span class="hljs-title function_">empty</span>();<br>                &lt;!--避免下拉框的值不变--&gt;<br>                $(childElements[i].<span class="hljs-property">element</span>).<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;&lt;option disabled selected value=&quot;&quot;&gt;&#x27;</span> + childElements[i].<span class="hljs-property">text</span> + <span class="hljs-string">&quot;&lt;/option&gt;&quot;</span>);<br>            &#125;<br>            &lt;!--使用循环解析后端传来的数据，并用使用js动态拼接html语言--&gt;<br>            <span class="hljs-keyword">if</span> (regionId !== <span class="hljs-string">&quot;&quot;</span>) &#123;<br>                <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; data.<span class="hljs-property">length</span>; i++) &#123;<br>                    $(childElements[<span class="hljs-number">0</span>].<span class="hljs-property">element</span>).<span class="hljs-title function_">append</span>(<span class="hljs-string">&quot;&lt;option value=&#x27;&quot;</span> + data[i].<span class="hljs-property">uuid</span> + <span class="hljs-string">&quot;&#x27;&gt;&quot;</span> + data[i].<span class="hljs-property">name</span> + <span class="hljs-string">&quot;&lt;/option&gt;&quot;</span>);<br>                &#125;<br>            &#125;<br>            form.<span class="hljs-title function_">render</span>();<br>        &#125;<br>    &#125;);<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="后端代码"><a href="#后端代码" class="headerlink" title="后端代码"></a>后端代码</h1><ul><li>获取子级数据接口。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 跳转下拉页面</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title function_">index</span><span class="hljs-params">(ModelAndView modelAndView)</span> &#123;<br>    modelAndView.addObject(<span class="hljs-string">&quot;province&quot;</span>, regionService.getRegionByParentId(<span class="hljs-string">&quot;&quot;</span>));<br>    modelAndView.setViewName(<span class="hljs-string">&quot;/selectPage&quot;</span>);<br>    <span class="hljs-keyword">return</span> modelAndView;<br>&#125;<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 查询地区信息</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@GetMapping(&quot;/select&quot;)</span><br><span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">getRegionByParentId</span><span class="hljs-params">(String regionId)</span> &#123;<br>    <span class="hljs-keyword">return</span> regionService.getRegionByParentId(regionId);<br>&#125;<br></code></pre></td></tr></table></figure><ul><li>查询当前 ID 下的子级数据。</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span><br>    uuid,<br>    pid,<br>    name<br><span class="hljs-keyword">FROM</span><br>    region<br><span class="hljs-keyword">WHERE</span><br>    pid <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;xx&#x27;</span><br></code></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;环境&quot;&gt;&lt;a href=&quot;#环境&quot; class=&quot;headerlink&quot; title=&quot;环境&quot;&gt;&lt;/a&gt;环境&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;后端框架：SpringBoot&lt;/li&gt;
&lt;li&gt;模板引擎：FreeMarker&lt;/li&gt;
&lt;li&gt;前端框架：JQuery&lt;/l</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/JavaScript/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="FreeMarker" scheme="http://www.loquy.cn/tags/FreeMarker/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/tags/JavaScript/"/>
    
    <category term="JQuery" scheme="http://www.loquy.cn/tags/JQuery/"/>
    
    <category term="Layui" scheme="http://www.loquy.cn/tags/Layui/"/>
    
  </entry>
  
  <entry>
    <title>二叉树的三种遍历方式</title>
    <link href="http://www.loquy.cn/posts/3718dbb0.html"/>
    <id>http://www.loquy.cn/posts/3718dbb0.html</id>
    <published>2022-06-22T02:53:35.000Z</published>
    <updated>2022-06-22T02:53:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><pre><code class="hljs">二叉树（Binary tree）是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式，即使是一般的树也能简单地转换为二叉树，而且二叉树的存储结构及其算法都较为简单，因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树，且有左右之分。二叉树是n个有限元素的集合，该集合或者为空、或者由一个称为根（root）的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成，是有序树。当集合为空时，称该二叉树为空二叉树。在二叉树中，一个元素也称作一个节点。</code></pre><h1 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h1><p><img src="/images/%E4%BA%8C%E5%8F%89%E6%A0%91.png" alt="求此二叉树的三种遍历顺序"></p><h2 id="前序遍历"><a href="#前序遍历" class="headerlink" title="前序遍历"></a>前序遍历</h2><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>遍历顺序：根结点 -&gt; 左子树 -&gt; 右子树</p><h3 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h3><p>用递归的方式实现遍历。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.leetcode.editor.tree;<br><br><span class="hljs-keyword">import</span> com.leetcode.utils.TreeNode;<br><br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 二叉树的前序遍历</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2021 /12/10 16:32</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">BinaryTreePreorderTraversal</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * The entry point of application.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> args the input arguments</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">left2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">4</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">5</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">left</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">2</span>, left2, right2);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right3</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">6</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">3</span>, <span class="hljs-literal">null</span>, right3);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">treeNode</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">1</span>, left, right);<br>        List&lt;Integer&gt; integers = preorderTraversal(treeNode);<br>        <span class="hljs-keyword">for</span> (Integer integer : integers) &#123;<br>            System.out.println(integer);<br>        &#125;<br>        TreeNode.show(treeNode);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Preorder traversal list.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> root the root</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title function_">preorderTraversal</span><span class="hljs-params">(TreeNode root)</span> &#123;<br>        List&lt;Integer&gt; res = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;Integer&gt;();<br>        preorder(root, res);<br>        <span class="hljs-keyword">return</span> res;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Preorder.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> root the root</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> res  the res</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">preorder</span><span class="hljs-params">(TreeNode root, List&lt;Integer&gt; res)</span> &#123;<br>        <span class="hljs-keyword">if</span> (root == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br>        <span class="hljs-comment">// 前序遍历，根-&gt;左-&gt;右的顺序</span><br>        <span class="hljs-comment">// 把当前节点的值添加到集合</span><br>        res.add(root.val);<br>        <span class="hljs-comment">// 递归遍历左子树，直到没有左子树</span><br>        preorder(root.left, res);<br>        <span class="hljs-comment">// 递归遍历右子树，直到没有右子树</span><br>        preorder(root.right, res);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出</p><figure class="highlight tap"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs tap">1<br>2<br>4<br>5<br>3<br>6<br>     <span class="hljs-number"> 1 </span>     <br>    /   \    <br> <span class="hljs-number"> 2 </span>     <span class="hljs-number"> 3 </span> <br> / \       \ <br>4  <span class="hljs-number"> 5 </span>      6<br></code></pre></td></tr></table></figure><h2 id="中序遍历"><a href="#中序遍历" class="headerlink" title="中序遍历"></a>中序遍历</h2><h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>遍历顺序：左子树 -&gt; 根结点 -&gt; 右子树</p><h3 id="代码示例-1"><a href="#代码示例-1" class="headerlink" title="代码示例"></a>代码示例</h3><p>用递归的方式实现遍历。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.leetcode.editor.tree;<br><br><span class="hljs-keyword">import</span> com.leetcode.utils.TreeNode;<br><br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 二叉树的中序遍历</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2021 /12/06 10:25</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">BinaryTreeInorderTraversal</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * The entry point of application.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> args the input arguments</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">left2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">4</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">5</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">left</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">2</span>, left2, right2);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right3</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">6</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">3</span>, <span class="hljs-literal">null</span>, right3);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">treeNode</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">1</span>, left, right);<br>        List&lt;Integer&gt; integers = inorderTraversal(treeNode);<br>        <span class="hljs-keyword">for</span> (Integer integer : integers) &#123;<br>            System.out.println(integer);<br>        &#125;<br>        TreeNode.show(treeNode);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Inorder traversal list.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> root the root</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title function_">inorderTraversal</span><span class="hljs-params">(TreeNode root)</span> &#123;<br>        List&lt;Integer&gt; res = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;Integer&gt;();<br>        inorder(root, res);<br>        <span class="hljs-keyword">return</span> res;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * Inorder.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> root the root</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> res  the res</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">inorder</span><span class="hljs-params">(TreeNode root, List&lt;Integer&gt; res)</span> &#123;<br>        <span class="hljs-keyword">if</span> (root == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-comment">// 递归结束条件，空则返回</span><br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br>        <span class="hljs-comment">// 中序遍历，左-&gt;根-&gt;右的顺序</span><br>        <span class="hljs-comment">// 递归遍历左子树，直到没有左子树</span><br>        inorder(root.left, res);<br>        <span class="hljs-comment">// 把当前节点的值添加到集合</span><br>        res.add(root.val);<br>        <span class="hljs-comment">// 递归遍历右子树，直到没有右子树</span><br>        inorder(root.right, res);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出</p><figure class="highlight tap"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs tap">4<br>2<br>5<br>1<br>3<br>6<br>     <span class="hljs-number"> 1 </span>     <br>    /   \    <br> <span class="hljs-number"> 2 </span>     <span class="hljs-number"> 3 </span> <br> / \       \ <br>4  <span class="hljs-number"> 5 </span>      6<br></code></pre></td></tr></table></figure><h2 id="后序遍历"><a href="#后序遍历" class="headerlink" title="后序遍历"></a>后序遍历</h2><h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>遍历顺序：左子树 -&gt; 右子树 -&gt; 根结点</p><h3 id="代码示例-2"><a href="#代码示例-2" class="headerlink" title="代码示例"></a>代码示例</h3><p>用递归的方式实现遍历。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.leetcode.editor.tree;<br><br><span class="hljs-keyword">import</span> com.leetcode.utils.TreeNode;<br><br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 二叉树的后序遍历</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@date</span> 2021/12/10 16:40</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">BinaryTreePostorderTraversal</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * The entry point of application.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> args the input arguments</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">left2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">4</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">5</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">left</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">2</span>, left2, right2);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right3</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">6</span>);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">right</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">3</span>, <span class="hljs-literal">null</span>, right3);<br>        <span class="hljs-type">TreeNode</span> <span class="hljs-variable">treeNode</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TreeNode</span>(<span class="hljs-number">1</span>, left, right);<br>        List&lt;Integer&gt; integers = postorderTraversal(treeNode);<br>        <span class="hljs-keyword">for</span> (Integer integer : integers) &#123;<br>            System.out.println(integer);<br>        &#125;<br>        TreeNode.show(treeNode);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * postorder traversal list.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> root the root</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the list</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title function_">postorderTraversal</span><span class="hljs-params">(TreeNode root)</span> &#123;<br>        List&lt;Integer&gt; res = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;Integer&gt;();<br>        postorder(root, res);<br>        <span class="hljs-keyword">return</span> res;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * postorder.</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> root the root</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> res  the res</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">postorder</span><span class="hljs-params">(TreeNode root, List&lt;Integer&gt; res)</span> &#123;<br>        <span class="hljs-keyword">if</span> (root == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br>        <span class="hljs-comment">// 后序遍历，左-&gt;右-&gt;根的顺序</span><br>        <span class="hljs-comment">// 递归遍历左子树，直到没有左子树</span><br>        postorder(root.left, res);<br>        <span class="hljs-comment">// 递归遍历右子树，直到没有右子树</span><br>        postorder(root.right, res);<br>        <span class="hljs-comment">// 把当前节点的值添加到集合</span><br>        res.add(root.val);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>输出</p><figure class="highlight tap"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs tap">4<br>5<br>2<br>6<br>3<br>1<br>     <span class="hljs-number"> 1 </span>     <br>    /   \    <br> <span class="hljs-number"> 2 </span>     <span class="hljs-number"> 3 </span> <br> / \       \ <br>4  <span class="hljs-number"> 5 </span>      6<br></code></pre></td></tr></table></figure><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p>查看此仓库</p><ul><li><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/utils/TreeNode.java">树类</a></li><li><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BinaryTreePreorderTraversal.java">前序</a></li><li><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BinaryTreeInorderTraversal.java">中序</a></li><li><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BinaryTreePostorderTraversal.java">后序</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;二叉树（Binary tree）是树形结构的一个重要类型。

许多实际问题抽象出来的数据结构往往是</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="算法" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/%E7%AE%97%E6%B3%95/"/>
    
    <category term="数据结构" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    
    <category term="算法" scheme="http://www.loquy.cn/tags/%E7%AE%97%E6%B3%95/"/>
    
    <category term="数据结构" scheme="http://www.loquy.cn/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
  </entry>
  
  <entry>
    <title>《玲音》剧情记录</title>
    <link href="http://www.loquy.cn/posts/242986fa.html"/>
    <id>http://www.loquy.cn/posts/242986fa.html</id>
    <published>2022-06-20T08:48:34.000Z</published>
    <updated>2022-06-20T08:48:34.000Z</updated>
    
    <content type="html"><![CDATA[<p class="note note-info">文章出处为我的<a href="https://www.bilibili.com/read/cv550761?spm_id_from=333.999.0.0">B站专栏</a>，写于2018年6月4日 上午。</p><p><img src="/images/%E8%90%8C%E8%90%8C%E7%9A%84%E7%8E%B2%E9%9F%B3.png" alt="萌萌的玲音"></p><h1 id="玲音"><a href="#玲音" class="headerlink" title="玲音"></a>玲音</h1><br><p>Present Day Present Time</p><h2 id="第一话"><a href="#第一话" class="headerlink" title="第一话"></a>第一话</h2><p>四方田千砂自杀。</p><p>乘坐电车的玲音觉得周围很吵说能不能安静，大家就真的不说话停下来看向她。</p><p>学校不少人收到已经死去的四方田千砂发的电子邮件引发了骚动。</p><p>回到家的玲音也收到了邮件，信中四方田千砂发说自己只是舍弃了肉体这封邮件就是证明，并且说这里存在神。玲音向妈妈说了这件事，玲音妈妈无动于衷。</p><p>玲音向爸爸要新的NAVI(个人电脑、移动终端等设备的统称)。</p><p>爸爸说无论是现实世界还是连线世界（Wired），大家彼此连系社会才得以运转。</p><p>爸爸问玲音为什么突然提起这件事，玲音说有想见的朋友。</p><p>画面切换到玲音在电车上，电车因为遭遇事故紧急停车，玲音看出窗外，电线上流下了血。</p><p>接着画面频繁切换到玲音站在路中央、地铁楼梯出口、学校广场电线杆上的电线，最后切换到玲音看着四方田千砂走到轨道上迎着电车相撞的场景。</p><p>画面切回玲音在教室在考试，玲音出现幻觉看到黑板上写着快点来到连线世界。</p><p>路上玲音看到四方田千砂说了声千砂，随即消失，等等，玲音说。</p><h2 id="第二话"><a href="#第二话" class="headerlink" title="第二话"></a>第二话</h2><p>这集比较奇怪，一开始夜总会里一个男人买了Accela〔Accela是一种大脑补充剂，通过纳米机械在体内产生固有频率的振动，以促进某种激素分泌，该激素会影响人的意识中对时间的感知，据服用者称:就像意识加速了一般。不仅如此，他还能有效刺激脑部运作，令服用者的计算能力提高二至十二倍不等，这种纳米机械本身虽然在24小时内几乎会被完全消化，但它会造成断续的闪回症状（幻觉重现）…〕。</p><p>玲音被同学认为像夜总会里的一个性格不同外貌很像的女生。</p><p>玲音收到一台全新的NAVI。</p><p>晚上玲音被同学邀去夜总会，在夜总会里吃药的男人好像发病了开枪打死人引发骚乱，玲音看上去出神了站着不动盯着男人，男人看到玲音说了一些奇怪的话：你有什么权利让我这么做，与我无关你这个傲慢的神，连线世界绝对不可以干扰现实世界，你到底是谁！玲音走过去说:无论在哪儿，人和人都彼此相连。男人就自杀了。</p><h2 id="第三话"><a href="#第三话" class="headerlink" title="第三话"></a>第三话</h2><p>玲音电车上幻听到一个男人对他说话：玲音是我…..玲音明白吗?玲音回答：谁?男子说：不是一个人。</p><p>课堂上玲音幻听到千砂说：我已经没有理由继续留在现实世界中了，对于现实世界而言，我是个可有可无的存在，当我明白这点的时候，我对舍弃自己的肉体已经没有丝毫的畏惧。然后一个机器合成的声音反复说：玲音是谁?</p><p>更衣室里爱丽丝说:说来奇怪呢，昨天我们亲眼目睹了人的死亡，尽管如此，却感觉只像看了场电影。同学A:虽然昨晚我们确实在那儿，但总觉得没什么真实感呢同学B:我也这么觉得，爱丽丝这件事还是别想得太深比较好。爱丽丝：不是这样，我觉得反而我们没想得太深才比较奇怪，你说呢玲音?接着玲音收到了一个奇怪物件。</p><p>路上玲音看着物件说:Psyche。</p><p>家中玲音问爸爸这是什么爸爸说不知道。还收到了一封电子邮件。</p><p>夜总会一个男子问玲音最近怎么没有见到你，咦你怎么变清纯了。下次开锐舞派对，组织安排就交给你咯。</p><p>玲音看到上次来时见到的三个小孩，拿出物件问知道这是什么吗？小鬼A:这个不是Psyche吗。小鬼B:真的假的。小鬼C:不会吧，我还是头一回亲眼。小鬼B:在哪儿买的？玲音：你知道这是什么吗？小鬼A:你在说啥啊，装上它(外形类似枪的机器)就算是这玩意也能毫无节制地访问连线世界呢。玲音:这个要怎么用呢?小鬼C:真逊连这个也不知道吗。小鬼B:把它卖给我吧卖给我吧。小鬼A:笨蛋你买的起吗。小鬼B:把它接入NAVI主处理器的背面，它会截取原有的信息并自动运行，其实就像拼装模型一样简单，只是要小心静电。小鬼C想要收钱并且对玲音说在网上见过她表现的很极端，前不久有个白痴在这家店惹事你也在吧，你有什么阴谋。玲音：你要我做什么。小鬼A要求和状态判若两人，疯狂人格的玲音约会一次。。</p><p>玲音的姐姐回家时被两个站在家门口带着奇怪眼镜的黑衣男子吓到，询问是谁后黑衣男说:你从没遇见过我们，要说为什么因为我们此刻并不在这里。</p><p>玲音姐姐看到玲音把Psyche装在NAVI上很惊讶。</p><p>最后，发出虚拟声音的玲音说了声：你回来啦姐姐。</p><h2 id="第四话"><a href="#第四话" class="headerlink" title="第四话"></a>第四话</h2><p>这集不断有人因为玩了一个叫PHANTOMa【基于其他游戏的网游，估计被改造过，问题在于两种程序合成的部分，协议里似乎存在漏洞，猜想会不会是Knights（不是实体，而是存在于网络上的一种思想，如同在连线世界中不断蔓延的宗教信仰一般）搞的鬼】的游戏而自杀，通过它可以在连线世界对战，玩家过的玩家，已经不玩的玩家，没有进入游戏也会在现实中乱入游戏世界，因为看到幻象感到害怕从而会发生逃跑哀嚎等行为最终有些玩家会崩溃自杀(其实是被迫自杀)。其中的一个男孩子在这乱入的过程幸运没有死，奇怪的是空中出现了一个投影虚拟的玲音在看着他。</p><p>玲音在改造NAVI过不了多久就能全范围、全动态的进入连新世界，爸爸提醒连线世界终究只是收发信息交流的空间，玲音说不是这样的，两者的界限没有划分的那么明确。</p><p>黑衣男子站在玲音家周围监视，玲音发现后说：给我滚开！然后黑衣男子马上滚蛋了，NAVI也发出提示说:已经入侵者已拦截。</p><h2 id="第五话"><a href="#第五话" class="headerlink" title="第五话"></a>第五话</h2><p>旁白：人类难道还会进化吗?有学说称：作为一种癌症发病率和其他动物相比极低的幼太持续（Neoteny）型生物，人类已无法再进化了。若真如此，人类真是进化成了一种多么愚蠢的生物啊，对推动自己的力量丝毫未觉，只为满足欲望而维持着肉体，不觉得无趣吗？人类终究只是这种东西。没必要继续过这种凄惨的人生了，因为人类已经创造出了用以逃生的出口。</p><p>玲音：那是什么？</p><p>旁白：网络，也就是连线世界，铃音。</p><p>玲音：你是谁？</p><p>旁白：我是神。</p><p>画面切回玲音的房间，玲音对着一个娃娃人偶说话，问它一些玲音不知道的事，娃娃说：你不知道的事不存在，我没法说不存在的事，事情的发生其实是先有预言的，有了预言这些事才会成真。玲音问：谁？ 谁会预言？</p><p>玲音走在马路上有人在发纸巾，玲音姐姐也收到了还被一个熊孩子搭讪不小心被泼到饮料，拿出纸巾擦衣服时发现纸巾上面写着：冥府已人满为患 死者将无处可去。</p><p>又切回房间，一个黑色人头雕像对着玲音说：预言正在实现。</p><p>玲音：若是这样的话 就不是预言了。</p><p>雕像：不是预言，所谓的历史不只是线性时间轴上的点，它们都是通过线连接在一起，不 ，应该说这些点都被人用线连接在一起比较好。</p><p>玲音：谁？ 是谁将它们连接起来的？</p><p>这回是漂浮在房间内好似虚拟的玲音妈妈说：把连线世界看成是现实世界的上层目录比较恰当，也就是说肉体等现实中的物体只不过是连线世界中的信息投射而成的全息影像。肉体、人脑的活动原本就是通过突触传递电信号引发的，说到底不过是单纯的物理现象而已，肉体存在的理由只是为了确认自身的存在。</p><p>这一段玲音姐姐被各种奇怪的现象吓死了，最后被关在厕所一整扇门写满了红色的去实现预言。。</p><p>这回是漂浮在房间内好似虚拟的玲音爸爸说：连线世界中传递的也许不只是电信号，如果将电话等电子通讯设备的发展视作连线世界形成的起源，不觉得在那一刻一个新的世界就已经诞生了吗？在这个现实世界中神的存在终究只是个概念，但在连线世界中或许能让宙斯般的化身得以显现，不知称其为神是否恰当，但他至少应该拥有像神话中的宙斯那样的支配力，连线世界中的宙斯所具的支配力也许已经影响现实世界了，没错以预言这种形式。</p><p>姐姐跑回家被吓出阴影来又碰到一个一模一样的自己，结果在玲音眼中变成透明的数据体，好似被侵入替换了。。</p><p>最后铃玲音回到房间对着那个被他改造的很科幻的NAVI说：今天 是谁？</p><h2 id="第六话"><a href="#第六话" class="headerlink" title="第六话"></a>第六话</h2><p>开头玲音爸爸被玲音改造的NAVI吓到了，玲音看着屏幕一脸陶醉的表情。</p><p>一个朦胧色彩变幻的空间玲音对着周围说：寄存器早已通过验证，下一代协议能尽快定下来就好了，这样我就能…我说你们为什么对我这么好？不是这个意思只是好奇，因为我没几个朋友，谢谢你们 Knights的各位。</p><p>一个傻孩子举着手望着天空。。</p><p>教室里玲音和同学聊起网络的朋友不告诉她们是谁说是个秘密。</p><p>傻孩子举着手望着天空*2</p><p>人群举着手望着天空*3</p><p>哇呜，天空中出现巨大的玲音幻影。</p><p>家里姐姐做在沙发看电视一脸被玩坏的表情好似丢了魂（感觉身体被掏空233）</p><p>玲音进入连线世界，黑暗中和一张巨大的嘴交谈想知道最近孩子流行的游戏，巨嘴说这个人或许能回答你的疑问。</p><p>杀害儿童的科学家，现实世界只是个在单人病房等死的老头。</p><p>去打听下KIDS吧巨嘴说。</p><p>霍奇森教授轮到你了你会告诉我吧，玲音说。</p><p>镜头切换到夕阳里。</p><p>玲音不断询问KIDS是谁，教授却答非所问在享受此刻233，玲音问给我看15年前的实验数据，教授说没打算让孩子们置于险境，玲音说不是十五年前的事，如今孩子们流行的游戏不是教授当初那个实验的再现吗?教授：大概是被谁从垃圾站捡了回来吧，我原本打算将所有的数据销毁。玲音：告诉我有关于15年前肯辛通实验的事。教授：大部分儿童都拥有极其微弱的PSI超心理能力，和那种不着边际的超能力不同，比如一点点的第六感还有像弯曲硬币这种程度的作用力。玲音：他们头上装的是什么？教授：我们称之为外部受体由下面这个系统来接收，这就是KIDS（看起来像黑盒子）虽然他们各自的力量及其微弱，但如果将这些力量汇聚起来…玲音：你在期盼什么？教授：那是无法预见的事小姐我想看的就是这个。玲音：你做了什么？教授：个人觉得科学应该不单只是去验证假设。玲音：不是说这个，那么孩子们会怎样你根本就没想过吧。教授：是的如之前所言外部受体将接受到的微弱脑电波进行转换，使大脑某部分的某种机制能得以增强，这就是KIDS系统的真面目。玲音：孩子们的PSI在合并时究竟产生了多么巨大的能量…我看不下去了够了。教授:我把KIDS系统彻底破坏了，但那套机器的设计图好像流传到了连线世界的某处，从此沉入了时间的沉渣中。玲音：然后有谁发现了它…教授：而且还更新了系统，使其无需借助外部受体便可引发现象，通过模拟硬件环境便使影响范围如此之广，真可谓优秀。铃音眼中含着泪光说：你只有这种想法吗？孩子们会怎样都无所谓吗。教授：我的想法改变不了孩子们已无法回归现实世界的事实，更何况现在受害的这些孩子。玲音：真是自以为是，那么现在使用的是那个系统吗？教授：小姐我说的太多现在累了，很高心见到你，虽然不知道你在连线世界里做什么也不清楚你的真实身份，但我感觉到你很强大，强到逆天233，如果这个连线世界有神存在的话，你一定是个被神祝福的孩子。玲音：我…我并不是…教授：模拟KIDS系统的那帮无赖，他们那种强大的力量究竟又是从哪儿来的呢。玲音：那帮无赖…教授：那么请容我先行告辞有点疲倦了，我的肉体已将消亡愿望也实现了。</p><p>切回房间，玲音坐着对着屏幕抱怨：烦死了，你们究竟在搞什么，为什么告诉我这么多？我也是你们手中的玩物吧？这一切都是场游戏吗？你们利用孩子们想做什么?只是觉得好玩？只要觉得好玩你们什么事都干？那样的话和一群猴子有什么区别（嘲笑），怎么不吭声了？没人回答吗？</p><p>此时那两个带着红外线眼镜的黑衣男又来到玲音家下面。玲音跑下楼质问他们是不是Knights,黑衣男说不是，刚下来房间的 冷却系统就爆炸了，黑衣男说被植入寄生炸弹，最后说是Knight干的就潇洒开着车走了。。</p><h2 id="第七话"><a href="#第七话" class="headerlink" title="第七话"></a>第七话</h2><p>科幻的房间里玲音对着屏幕说着：不 不是那样，我只是看着而已因为连线世界中的我…嗯 已不再是我，嗯 不是很清楚，咦 你说谁？门口：姐姐嘴上说着但没发出声。。</p><p>一个男子带着类似VR的机器走在大街上说着：连线世界和现实世界连接在一条线上，无论哪个世界我都可以生存，不管肉体位于何处，意识都能去往任何地方。</p><p>办公室一位女士对着经理说：E发动（据说一种永动机）机集团的午宴就要开始了。</p><p>经理对着屏幕奸笑：这次要玩什么呢？</p><p>教室里玲音在偷玩着外形类似手机的机器。</p><p>一个肥宅对着屏幕说：没错 我和你们这群笨蛋有着天壤之别。</p><p>切回楼顶：爱丽丝和玲音说最近变得不一样了，我们带着你到处玩是为了不让你孤单，希望你变得开朗些，真心为你着想，但是玲音你不高兴的话我想你道歉。玲音：我没觉得…没觉得不高兴（紧张的发抖）。爱丽丝说太好了，铃音感谢爱丽丝为她担心，爱丽丝说谁让我们是朋友呢,回头见。</p><p>新闻：情报中心防火墙被人攻破，目前连线世界一片混论。</p><p>连线世界再讨论Knights。 Knights据称是个在连线世界中拥有强大势力的算法骑士团，组成人员不明，他们不单对情报进行操控，而且还从事非法信息设备的开发和流通。</p><p>快递男想勾引家庭主妇被识破，家庭主妇也说了奇怪的话，连线世界也和现实世界一样。</p><p>路上黑衣男邀请玲音跟他走，玲音问你们是谁，黑衣男摘掉面具说跟我走就告诉你。</p><p>VR男走在路上在求着加入Knight，突然镜头闪过玲音的虚拟人像，男子问道是谁？</p><p>玲音被带到橘综合研究所，被一男子请求修好电脑，打开电脑虚拟铃音对着VR男说八嘎。</p><p>关掉电脑男子对玲音说：Knights是个不同寻常的组织，Knights对连线世界中的你特别感兴趣，他们利用你达到某种目的，要不惜动用任何手段组织他们。玲音问你们是谁。</p><p>切回VR男追寻着Knights想加入他们，影像里闪现出之前的经理、肥宅、主妇。</p><p>男子问道你和连线世界的玲音是同一个人吗？你究竟是谁？你的父母是你的亲生父母吗？你的姐姐是你的亲姐姐吗？玲音回答你在说什么？这不是理说当然的吗。男子：你父亲的生日是哪天？你母亲的生日是哪天？一连串问题玲音回答不上来。快要崩溃了，突然强硬的虚拟玲音仿佛上了现实世界玲音的身，怼回男子真啰嗦啊无聊至极尽说些没用的….男子：喔是连线世界的玲音吗？玲音：是又如何？男子：你应该也知道把即使不借助任何设备，也能将连线世界与现实世界之间的界限逐步瓦解。玲音：那又怎样？男子：我认为这种行为非常危险。玲音：那不是很有趣么，哼。走的时候被黑衣男拉住说：有危险的是你自己。男子训斥卡尔，正如他说的那样有趣的事要发生了，静观其变。</p><p>主妇扔掉寄来已经烧坏的硬件，VR男死在草地上。</p><h2 id="第八话"><a href="#第八话" class="headerlink" title="第八话"></a>第八话</h2><p>旁白：你也想伤害自己吗？渴望拥有一段心如刀割的回忆吗?那就千万别移开视线…</p><p>线上世界玲音和一道声音交谈：六代协议下的数据吞吐量已经见顶，第七代协议正在建立，一旦掌控了协议实际就掌控了连线世界的经济，因此各方在争斗，收拾这一局面的是橘综研。</p><p>回到房间姐姐依旧被玩坏一样。。父母因为玲音谈到有人说在橘综研的事很诡异盯着玲音。</p><p>学校爱丽丝和几个同学问玲音连线世界的某件事是不是他做的。最后爱丽丝看到玲音紧张的样子马上说没事不是玲音做的（如果这都不算爱）。</p><p>又来意识流，黑暗的空间里一群人讨论着各种八卦，玲音说很烦。接着一个男性的声音出现了问道你不觉得有趣吗？你在找我吧。玲音：传说中的神登场了？</p><p>神的定义是什么呢？世界的造物主？那么我不是。掌控世界的全能统治者？那就高估我了。</p><p>玲音：你在哪儿？</p><p>如果所谓的神是这个世界普遍存在的事物，那么没错你可以这么称呼我，我只是在对世界的走向稍加干涉。</p><p>玲音：你究竟是谁？</p><p>我就是你，你应该也发觉了吧？很久以前这个连线世界中就一直存在着另一个你。你不过是她投射出的全息影像，你只是一具肉体。</p><p>玲音：这种事谁会信啊，不可能有这种事。</p><p>可是现实世界的你与现在的你两者人格截然不同，你自己也这么觉得吧？</p><p>玲音：但我还是我…</p><p>切回到教室，所有人和父母一样诡异的盯着玲音。。跑出去也是同样的情况。玲音不断的在问爱丽丝在那里。抱膝哭着自责另一个在连线世界的我到底做了什么?</p><p>卧槽切回到房间爱丽丝在想着老师自慰，一旁坏人格的玲音在幸灾乐祸。</p><p>爱丽丝问果然是散布的吗，你一直在暗中偷窥我吗？</p><p>切回玲音房间身体插着线躺着眼中哭着好似很难受。</p><p>意识流，坏玲音笑了和玲音互怼。你不是我，我不会做这种事，为什么要模仿我所厌恶的那个自己？（坏玲音奸笑）玲音掐着坏玲音。坏玲音说我在自杀吗？（嘲讽）玲音说为什么你有体温？为什么要让我感觉到你的体温。坏玲音：因为…我不就是你吗。玲音：不是的！</p><p>切回另一个意识所谓的神又出现了告诉玲音到处都是你你不断着偷窥别人的隐私，连线世界就应该共享。</p><p>玲音：你说的这些全都是骗人的。</p><p>为什么？</p><p>玲音：爱丽丝她们看到了连线世界的我，而我当时并不在这里，只要我能分辨自己，我的自我就与我同在。如果是像你说的一样的话，大家被玲音偷窥的这段记忆，应该都可以被消除。</p><p>说的对，用你与生俱来的能力试试看吧。</p><p>嘀嘀嘀，正在删除…</p><p>结果大家都忘了玲音，生活中被坏玲音替代了。。</p><p>屏幕前玲音说：我还是我对吧？除了我之外的我根本不存在对吧？(含着眼泪)</p><h2 id="第九话"><a href="#第九话" class="headerlink" title="第九话"></a>第九话</h2><p>旁白：若想摆脱痛苦就去信奉神吧，不管你是否相信神始终都在你的身旁。</p><p>切换到三次元影像，1947.7.4飞船坠落在美国墨西哥州的沙漠，真实面目至今未被证实，而当时的猜测却被当作真相流传下来成为了历史。</p><p>卧槽玲音房间门口出现外星人一下又消失了。</p><span style="font-size: x-small; ">三次元：1984年电视剧制片人詹姆·山德拉家中收到一个匿名邮包，牛皮纸封套里装着尚未冲洗的胶卷，照片上拍摄的是所谓的MJ-12文件。据该文件所述罗斯威尔事件发生后，以当时的中情局局长罗斯科·希伦科特为首的12人成立了一个直接受命于总统的组织并于外星生物签订了秘密条约，经验证这份文件上杜鲁门总统的署名是从其他文件上复制过来的，当时被指明为MJ-12成员之一的正是麻省理工学院工程学院院长范内瓦·布什。</span><br><br><p>玲音进入连线世界问着一群影子一样的人：究竟要怎样才能让已经发生的事变成从未发生过？</p><p>A：是玲音啊原来如此。</p><p>玲音：我对你一无所知，而你却对我一清二楚。</p><p>A:情报未必总会流向双方，自从你在连线世界上诞生的那一刻起，你就一直存在于此，在这里你是自由的。</p><p>玲音：都说了那不是我！</p><p>A：那么我们是从何时开始存在于此的？至少不会是在这个世界诞生之初吧。</p><p>B：与此无关，只要存在本身被记忆过，就应该会有记录。</p><span style="font-size: x-small; ">三次元：范内瓦·布什在1945年发表了一个记录扩展设想（MEMEX），该系统能将微缩胶卷上存储的信息呈现在半透明的屏幕上，他所构思的是这一种信息压缩和快速读取的技术，当时正在指挥核爆试验曼哈顿计划的布什，在计算机诞生之前就为现在的多媒体技术打下了基础。</span><br><br><p>夜店男和玲音说有个你忘记的东西，一块装在信封的硬件。</p><span style="font-size: x-small; ">三次元：约翰·李利为了探索人的无意识曾利用印度的麻药和隔离箱做过感觉剥夺实验，实验过程中他认为自己借助通信网络和宇宙的某种存在取得了连接，李利将引导他的那个存在称之为E.C.C.O——地球暗号管制局。之后李利把研究转向了海豚间的交流，海豚可通过自身发出的超声波在水中建立起范围极广的交流网络。</span><br><br><p>夜店和三个熊孩子交谈，之前做过约定所以玲音说一起约会。这个熊孩子竟然说要约的不是现在的你。。玲音说：都一样，我就是我，只有一个我。</p><p>带着熊孩子参观玲音的间，熊孩子看着科幻的房间很兴奋。</p><p>玲音问熊孩子夜店男给送的硬件是什么，你是Knights的一员吧。</p><p>熊孩子被怀疑是夜店铃音出现时的犯人了，操控别人的记忆。</p><p>家里爸爸妈妈姐姐的行为都很奇怪。</p><p>玲音播放了一首令人产生幻觉的音乐，熊孩子说不是他干的。</p><p>逼问下原来这个硬件是一块非易失性内存，可以改写已有的记忆。</p><p>熊孩子说Knights不只是黑客，是为了实现唯一真理而奋斗的执行者，你很奇怪才会被盯上。</p><p>玲音说不大明白唯一的真理是什么？真理代表着强大象征着正义熊孩子说。</p><p>卧槽熊孩子强吻了玲音！！！还是舌吻把口香糖传到玲音嘴里。。。</p><span style="font-size: x-small; ">三次元：泰德·纳尔逊继承了范内瓦·布什和约翰·李利这两位异端先行者的理念，发表了名为Xanadu的数据库设想——将一个巨大电子图书馆以静止卫星形式发射到运行轨道上，地球上的各种终端在任何角落都能通过电波和电话线来使用它。Xanadu是传说中蒙古的理想乡在哪里所有的文字文化永远不会消逝，而在现实世界中令其实现的正式超文本这一概念，它的设计者泰德·纳尔逊定会名留史册吧。</span><br><br><p>玲音检查NAVI内存知道了自己不是亲生的。很困惑。</p><span style="font-size: x-small; ">三次元：地球又其特定的而电磁波，在电离层和地表之间，一直存在着频率为8Hz的极低频电磁波，它被称为舒曼共振。这种地球常年发出的电磁波可看作是地球的脑波，它会对人类产生怎样的影响，至今仍未判明，地球人口数已达到了人脑神经元的数量，道格拉斯·洛希科夫主张通过网络将地球上的人类互相连接，以唤醒地球自身的意识，如今网络已进化成为神经系统，就像人脑中突触连接神经元那样，整个地球正在转变为一个神经网络。曾担任橘宗研研究主任的英利政美，进一步发展了这一覆盖地球的神经网络假说，据他所称地球上所有人甚至不需要借助任何设备，就可以在无意识下连接网络，不仅如此他还擅自将加密后的舒曼共振因子写入了第七代网络协议中。</span><br><br><p>橘宗研知道此事后解雇了英利政美，一周后山手线上发现了英利政美被碾压后的尸体。</p><p>伴随着嗡嗡的电流声结尾出现了——</p><p>穿着白色长袍腰上绑着绷带脸上涂着红色印记的一个妖异的长发男子。</p><h2 id="第十话"><a href="#第十话" class="headerlink" title="第十话"></a>第十话</h2><p>开头玲音与这个妖异男子谈了一段话知道他就是死去的英利政美。</p><p>对话如下：</p><p>玲音：你就是神？</p><p>英利政美：没错我就是神。</p><p>我搞不懂你为什么你会是神？你不是已经死了吗？一个死人怎么可能会成为神。</p><p>玲音：我明白了肉体只是累赘，所谓的死只是舍弃肉体而已。</p><p>英利政美：那是千砂…</p><p>玲音：是的没错，我进化了网络协议统治了连线世界。</p><p>英利政美：对你确实这么做了，但协议只是个约定。</p><p>玲音：对不过我将加密后的作用代码写入了更高级的协议层。</p><p>英利政美：那又如何？</p><p>玲音：这个协议中混入了压缩后的信息。</p><p>英利政美：什么信息？</p><p>玲音：人的记忆我英利政美本人的思想、经历、记录、情绪…</p><p>英利政美：这又意味着什么呢？</p><p>玲音：以匿名用户的身份在连线世中永生，利用信息统治连线世界。</p><p>英利政美：你觉得该如何形容这种存在？</p><p>玲音：神。</p><p>英利政美：神根本不存在。</p><p>玲音：没错即使普遍存在于这个世界能对这个世界施加影响，但没有信徒就不足以为神。</p><p>英利政美：不过你拥有信徒，不，应该说制造了信徒。</p><p>玲音：Knights…</p><p>英利政美：对你而言肉体只是累赘玲音…</p><p>玲音：一派胡言！</p><p>切回教室玲音的座位没了，别人也没发现她，看起来很失落。</p><p>一直在陈述自己是存在的，慢慢怀疑自己是错的不可以拥有肉体。而爱丽丝说世界不需要你，很受打击。</p><p>切回家也空荡荡很久没人住了一样。玲音爸爸突然出现跟他道别，说工作就到此为止。</p><p>玲音说别留下我一个人，他回答说到连线世界所有人都会欢迎你，你就是这样一种存在。</p><p>连线世界玲音问虚拟的我是不是Knights制造出来的，有声音回答早在连线世界诞生之前，他们就一直在利用人与人之间存在的无形网络——集体无意识。</p><p>Knights的成员名单突然出现在网络新闻里。之前的经理男被黑衣男杀死了，肥宅也是，主妇也是，各处都有成员死去。</p><p>玲音房间里黑衣男说连线世界中英利政美的残留思念程序终将被清除，我们的雇主正在对第七代协议的代码进行全面改写，我们不需要神，虽然我们至今无法理解你这个存在。不过我喜欢你。</p><p>刮风的马路上——</p><p>玲音：该怎么办？</p><p>英利政美：那么如何是好呢。</p><p>玲音：你的信徒消失了。</p><p>英利政美：那样我就不再是神了，不过还没有全部消失，只要还有一个信徒我就让仍是神。</p><p>玲音：那个人是谁？</p><p>英利政美：讨厌说的就是你啊玲音，你能成为你都是我的功劳，你原本诞生于连线世界中，你只是连线世界的传说，只是连线世界的童话中的主人公。</p><p>玲音：骗人…</p><p>英利政美：现实世界中的岩仓玲音只是她的全息投影，是用人造核糖体制成的人造人，你原本并没有实体。</p><p>玲音：骗人…</p><p>英利政美：虚假的家庭虚假的朋友，没错所有的一切都是骗人的。</p><p>玲音：骗人… 你在骗人…（含泪）</p><p>英利政美：可怜的玲音孤单一人。但还有我，还有爱着你的我，我把你送到了这个世界，你应该会爱我才对，我是你的创造者。爱我吧。好吗玲音。</p><p>玲音：另一个…</p><p>英利政美：嗯？</p><p>玲音：另一个我…</p><p>英利政美：不是另一个，那是真正的你。</p><p>玲音：随你怎么说！</p><h2 id="第十一话"><a href="#第十一话" class="headerlink" title="第十一话"></a>第十一话</h2><p>记忆并不是模糊不清。</p><p>然后回忆了此前的种种事件走马观花。</p><p>意识流一幕幕画面。</p><p>切回房间英利政美对玲音说：你是个拥有肉体的可执行程序。</p><p>路上四方田千砂出现了，死去的酒吧暴走男出现了，一个低落一个兴奋。</p><p>男子逼着铃音舍弃肉体，千砂低落的说死没那么简单。</p><p>玲音跑到爱丽丝房间和她说要删除之前所有发生的事。</p><p>学校里爱丽丝和老师的事被删了没人记得了。</p><h2 id="第十二话"><a href="#第十二话" class="headerlink" title="第十二话"></a>第十二话</h2><p>玲音发邮件发给爱丽丝说那些不愉快的事改写掉就是了。</p><p>英利政美一波理论要把人类从身体挣脱出来共享感知等等，鼓动玲音。</p><p>车里两个黑衣男交谈：雇主和英利政美是串通的是一件阴谋。</p><p>地下室质问雇主连线世界与现实世界无需任何设备就能连接有什么目的？雇主只说了会发生美妙的事拭目以待。结果两个人好像中病毒般被杀死了。</p><p>爱丽丝访问玲音的家，问玲音为什么唯独让我保留原来的记忆？玲音：只有你是我真正的朋友。我本身就是一个用于破坏连线世界与现实世界的间隔的程序。</p><p>爱丽丝：不是这样的。</p><p>英利政美反驳怼了一波爱丽丝。</p><p>玲音又怼了一波英利政美。反杀！</p><p>玲音：你只是接触了各种设备与连线世界的关联，没有电话、电视和网络你就什么也做不到。</p><p>英利政美：没错这些不都是人类进化过程中的产物吗，人类位于进化的顶点有权拥有比它们更高级的机能。</p><p>玲音：谁给的权力？你在第七代网络协议中编入了于地球的固有振动相同的代码，因此才得以创造出能让集体无意识转化为意识的程序，这真的是你自己想出来的吗？</p><p>英利政美：你究竟想说什么？难道…难道你想说这个世界真有所谓的神吗？</p><p>玲音：不管怎样失去肉体的你是不会明白的。</p><p>英利政美：骗人！我…是无所不能的！我让你在现实世界中拥有了肉体！我让普遍存在于连线世界中的你拥有了自我！可你…</p><p>玲音：假设我是这样那么你呢？</p><p>英利政美：我不一样！我…</p><p>暴走一波</p><p>玲音：连线世界不是现实世界的上级目录。</p><p>英利政美：什么意思？</p><p>玲音：你确实是连线世界的神那么在连线世界诞生之前呢？你只是一直在等待连线世界发展到今天，你只是神的代理人。</p><p>英利政美：你说什么…胡说！</p><p>暴走第二波</p><p>玲音：你不是不需要肉体吗？</p><p>英利政美被这句将死崩溃消失了。</p><h2 id="第十三话"><a href="#第十三话" class="headerlink" title="第十三话"></a>第十三话</h2><p>开头虚拟玲音在问自己是谁。</p><p>玲音向爱丽丝道歉之前做的是错的。</p><p>镜头出现重置一切的字体。</p><p>伴随着BGM</p><p>世界又回归正常。死的人也都复活了。英利政美竟然也复活了。</p><p>但是玲音不见了谁也不记得她。(虐)</p><p>一波意识流，两个玲音在谈论重置世界对与错，利与弊。</p><p>纠结于自身的存在。</p><p>连线世界其实只是连接而已，那么连接另一端通往哪里？</p><p>人类有必要了解这个吗。</p><p>就算对此一无所知人类不是依旧走到了今天。</p><p>玲音讨厌这种说法。</p><p>玲音是任何事物是观察者。</p><p>（你是什么你从哪里来要到那里去）</p><p>最后类似神的存在幻化成玲音爸爸和伤心的玲音交谈…</p><p>切回马路天桥上玲音与长大后的爱丽丝相遇了，爱丽丝还是不记得玲音。</p><p>玲音望着爱丽丝背影说着没错无论何时我们都能相见。</p><p>结尾虚拟玲音说我在这里所以我们永远都在一起。</p><p><img src="/images/%E7%8E%B2%E9%9F%B3.png"></p><p>完</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p class=&quot;note note-info&quot;&gt;
文章出处为我的&lt;a href=&quot;https://www.bilibili.com/read/cv550761?spm_id_from=333.999.0.0&quot;&gt;B站专栏&lt;/a&gt;，写于2018年6月4日 上午。
&lt;/p&gt;

&lt;p</summary>
      
    
    
    
    <category term="生活" scheme="http://www.loquy.cn/categories/%E7%94%9F%E6%B4%BB/"/>
    
    <category term="动漫" scheme="http://www.loquy.cn/categories/%E7%94%9F%E6%B4%BB/%E5%8A%A8%E6%BC%AB/"/>
    
    
    <category term="动漫" scheme="http://www.loquy.cn/tags/%E5%8A%A8%E6%BC%AB/"/>
    
  </entry>
  
  <entry>
    <title>《文学回忆录》读书笔记</title>
    <link href="http://www.loquy.cn/posts/9883083f.html"/>
    <id>http://www.loquy.cn/posts/9883083f.html</id>
    <published>2022-06-17T05:46:05.000Z</published>
    <updated>2022-06-17T05:46:05.000Z</updated>
    
    <content type="html"><![CDATA[<p>一、前言</p><p>关于《文学回忆录》（木心口述，陈丹青笔录）的一些读后笔记，主要记录些文学史上重要的作者和书籍，汇集成书目，以书找书，方便日后查看，写于2020年初。</p><p>二、史诗</p><p>《伊利亚特》、《奥德赛》（荷马，古希腊）。</p><p>三、宗教</p><p>《圣经》新旧约。</p><p>四、各大学家（作家、哲学家、文学家、史学家）</p><p>中国：老子、庄子、墨子、孔子、苏东坡、司马迁、曹雪芹。<br>外国：尼采、莎士比亚、福楼拜、雨果、叔本华、易卜生、爱伦坡、托尔斯泰、巴尔扎克、陀思妥耶夫斯基、莫泊桑、卡夫卡、加缪、普希金、伍尔芙夫人、高尔基、契科夫、纪德、歌德、席勒。</p><p>五、诗人</p><p>中国：李白、杜甫、陶渊明、屈原。<br>外国：拜伦、雪莱、海涅。</p><p>六、书</p><p>中国：《红楼梦》、《诗经》、《道德经》、《金瓶梅》、《水浒》、《浮生六记》、《易经》。<br>外国：《地粮》(纪德，盛澄华译本)。</p><p>七、观点</p><p>某个方向的书，要由浅到深看。<br>文学是人学。<br>时时要有死的恳切，活着就知道该如何了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;一、前言&lt;/p&gt;
&lt;p&gt;关于《文学回忆录》（木心口述，陈丹青笔录）的一些读后笔记，主要记录些文学史上重要的作者和书籍，汇集成书目，以书找书，方便日后查看，写于2020年初。&lt;/p&gt;
&lt;p&gt;二、史诗&lt;/p&gt;
&lt;p&gt;《伊利亚特》、《奥德赛》（荷马，古希腊）。&lt;/p&gt;
&lt;p&gt;三、</summary>
      
    
    
    
    <category term="生活" scheme="http://www.loquy.cn/categories/%E7%94%9F%E6%B4%BB/"/>
    
    <category term="读书笔记" scheme="http://www.loquy.cn/categories/%E7%94%9F%E6%B4%BB/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="木心" scheme="http://www.loquy.cn/tags/%E6%9C%A8%E5%BF%83/"/>
    
  </entry>
  
  <entry>
    <title>在 LeetCode 上学习的算法和数据结构</title>
    <link href="http://www.loquy.cn/posts/b091fa12.html"/>
    <id>http://www.loquy.cn/posts/b091fa12.html</id>
    <published>2022-06-15T03:08:06.000Z</published>
    <updated>2022-06-15T03:08:06.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="LeetCode"><a href="#LeetCode" class="headerlink" title="LeetCode"></a>LeetCode</h1><p>在 <a href="https://leetcode.cn/">LeetCode</a> 上学习算法和数据结构。</p><h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><table><thead><tr><th align="center">序号</th><th align="center">题目</th><th align="center">题解</th><th align="center">标签</th><th align="center">难度</th></tr></thead><tbody><tr><td align="center">1</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/TwoSum.md">两数之和</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/TwoSum.java">Java</a></td><td align="center"><code> 数组</code> <code> 哈希表</code></td><td align="center">简单</td></tr><tr><td align="center">26</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RemoveDuplicatesFromSortedArray.md">删除有序数组中的重复项</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/RemoveDuplicatesFromSortedArray.java">Java</a></td><td align="center"><code>数组</code>  <code>双指针</code></td><td align="center">简单</td></tr><tr><td align="center">27</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RemoveElement.md">移除元素</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/RemoveElement.java">Java</a></td><td align="center"><code>数组</code>  <code>双指针</code></td><td align="center">简单</td></tr><tr><td align="center">35</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/SearchInsertPosition.java">搜索插入位置</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/SearchInsertPosition.md">Java</a></td><td align="center"><code> 数组</code> <code> 二分查找</code></td><td align="center">简单</td></tr><tr><td align="center">53</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MaximumSubarray.md">最大子数组和</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/MaximumSubarray.java">Java</a></td><td align="center"><code>数组</code> <code>分治</code> <code>动态规划</code></td><td align="center">简单</td></tr><tr><td align="center">66</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PlusOne.md">加一</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/PlusOne.java">Java</a></td><td align="center"><code> 数组</code> <code> 数学</code></td><td align="center">简单</td></tr><tr><td align="center">88</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MergeSortedArray.md">合并两个有序数组</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/MergeSortedArray.java">Java</a></td><td align="center"><code> 数组</code> <code> 双指针</code> <code> 排序</code></td><td align="center">简单</td></tr><tr><td align="center">108</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ConvertSortedArrayToBinarySearchTree.md">将有序数组转换为二叉搜索树</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/ConvertSortedArrayToBinarySearchTree.java">Java</a></td><td align="center"><code>数组</code> <code>二叉搜索树</code> <code>分治</code></td><td align="center">简单</td></tr><tr><td align="center">118</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PascalsTriangle.md">杨辉三角</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/PascalsTriangle.java">Java</a></td><td align="center"><code> 数组</code> <code> 动态规划</code></td><td align="center">简单</td></tr><tr><td align="center">136</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/SingleNumber.md">只出现一次的数字</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/SingleNumber.java">Java</a></td><td align="center"><code> 位运算</code> <code> 数组</code></td><td align="center">简单</td></tr><tr><td align="center">169</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MajorityElement.md">多数元素</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/MajorityElement.java">Java</a></td><td align="center"><code>数组</code> <code>哈希表</code> <code>分治</code> <code>计数</code> <code>排序</code></td><td align="center">简单</td></tr><tr><td align="center">228</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/SummaryRanges.md">汇总区间</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/SummaryRanges.java">Java</a></td><td align="center"><code> 数组</code></td><td align="center">简单</td></tr><tr><td align="center">268</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MissingNumber.md">丢失的数字</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/MissingNumber.java">Java</a></td><td align="center"><code> 位运算</code> <code> 数组</code> <code> 哈希表</code> <code> 数学</code> <code> 排序</code></td><td align="center">简单</td></tr><tr><td align="center">283</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MissingNumber.md">移动零</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/MoveZeroes.java">Java</a></td><td align="center"><code> 位运算</code> <code> 数组</code> <code> 哈希表</code> <code> 数学</code> <code> 排序</code></td><td align="center">简单</td></tr><tr><td align="center">303</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RangeSumQueryImmutable.md">区域和检索 - 数组不可变</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/RangeSumQueryImmutable.java">Java</a></td><td align="center"><code> 设计</code> <code> 数组</code> <code> 前缀和</code></td><td align="center">简单</td></tr><tr><td align="center">349</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/IntersectionOfTwoArrays.md">两个数组的交集</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/IntersectionOfTwoArrays.java">Java</a></td><td align="center"><code>数组</code> <code>哈希表</code> <code>双指针</code> <code>二分查找</code> <code>排序</code></td><td align="center">简单</td></tr><tr><td align="center">448</td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/FindAllNumbersDisappearedInAnArray.md">找到所有数组中消失的数字</a></td><td align="center"><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/array/FindAllNumbersDisappearedInAnArray.java">Java</a></td><td align="center"><code>数组</code> <code>哈希表</code></td><td align="center">简单</td></tr></tbody></table><h2 id="链表"><a href="#链表" class="headerlink" title="链表"></a>链表</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>2</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/AddTwoNumbers.md">两数相加</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/AddTwoNumbers.java">Java</a></td><td><code>递归</code> <code>链表</code> <code>数学</code></td><td>中等</td></tr><tr><td>21</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MergeTwoSortedLists.md">合并两个有序链表</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/MergeTwoLists.java">Java</a></td><td><code>递归</code> <code>链表</code></td><td>简单</td></tr><tr><td>83</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RemoveDuplicatesFromSortedList.md">删除排序链表中的重复元素</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/RemoveDuplicatesFromSortedList.java">Java</a></td><td><code>链表</code></td><td>简单</td></tr><tr><td>141</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/LinkedListCycle.md">环形链表</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/LinkedListCycle.java">Java</a></td><td><code>哈希表</code> <code>链表</code> <code>双指针</code></td><td>简单</td></tr><tr><td>160</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/IntersectionOfTwoLinkedLists.md">相交链表</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/IntersectionOfTwoLinkedLists.java">Java</a></td><td><code>哈希表</code> <code>链表</code> <code>双指针</code></td><td>简单</td></tr><tr><td>203</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RemoveLinkedListElements.md">移除链表元素</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/RemoveLinkedListElements.java">Java</a></td><td><code>递归</code> <code>链表</code></td><td>简单</td></tr><tr><td>206</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ReverseLinkedList.md">反转链表</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/ReverseLinkedList.java">Java</a></td><td><code>递归</code> <code>链表</code></td><td>简单</td></tr><tr><td>234</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PalindromeLinkedList.md">回文链表</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/PalindromeLinkedList.java">Java</a></td><td><code>栈</code> <code>递归</code> <code>链表</code> <code>双指针</code></td><td>简单</td></tr><tr><td>237</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/DeleteNodeInALinkedList.md">删除链表中的节点</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/linkedlist/DeleteNodeInALinkedList.java">Java</a></td><td><code>链表</code></td><td>简单</td></tr></tbody></table><h2 id="数学"><a href="#数学" class="headerlink" title="数学"></a>数学</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>7</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ReverseInteger.md">整数反转</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/Reverse.java">Java</a></td><td><code>数学</code></td><td>中等</td></tr><tr><td>9</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PalindromeNumber.md">回文数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/IsPalindrome.java">Java</a></td><td><code>数学</code></td><td>简单</td></tr><tr><td>29</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/DivideTwoIntegers.md">两数相除</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/DivideTwoIntegers.java">Java</a></td><td><code>位运算</code>  <code>数学</code></td><td>中等</td></tr><tr><td>69</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/Sqrtx.md">x 的平方根</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/Sqrtx.java">Java</a></td><td><code>数学</code> <code>二分查找</code></td><td>简单</td></tr><tr><td>70</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ClimbingStairs.md">爬楼梯</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/ClimbingStairs.java">Java</a></td><td><code>记忆化搜索</code> <code>数学</code> <code>动态规划</code></td><td>简单</td></tr><tr><td>202</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/HappyNumber.md">快乐数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/HappyNumber.java">Java</a></td><td><code>哈希表</code> <code>数学</code> <code>双指针</code></td><td>简单</td></tr><tr><td>231</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PowerOfTwo.md">2 的幂</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/PowerOfTwo.java">Java</a></td><td><code>位运算</code> <code>递归</code> <code>数学</code></td><td>简单</td></tr><tr><td>258</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/AddDigits.md">各位相加</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/AddDigits.java">Java</a></td><td><code>数学</code> <code>数论</code> <code>模拟</code></td><td>简单</td></tr><tr><td>263</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/UglyNumber.md">丑数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/UglyNumber.java">Java</a></td><td><code>数学</code></td><td>简单</td></tr><tr><td>326</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PowerOfThree.md">3 的幂</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/PowerOfThree.java">Java</a></td><td><code>递归</code> <code>数学</code></td><td>简单</td></tr><tr><td>338</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/CountingBits.md">比特位计数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/CountingBits.java">Java</a></td><td><code>位运算</code> <code>动态规划</code></td><td>简单</td></tr><tr><td>342</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PowerOfFour.md">4 的幂</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/PowerOfFour.java">Java</a></td><td><code>位运算</code> <code>递归</code> <code>数学</code></td><td>简单</td></tr><tr><td>367</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ValidPerfectSquare.md">有效的完全平方数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/ValidPerfectSquare.java">Java</a></td><td><code>数学</code> <code>二分查找</code></td><td></td></tr><tr><td>405</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ConvertANumberToHexadecimal.md">数字转换为十六进制数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/ConvertANumberToHexadecimal.java">Java</a></td><td><code>位运算</code> <code>数学</code></td><td>简单</td></tr><tr><td>441</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ArrangingCoins.md">排列硬币</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/math/ArrangingCoins.java">Java</a></td><td><code>数学</code> <code>二分查找</code></td><td>简单</td></tr></tbody></table><h2 id="队列"><a href="#队列" class="headerlink" title="队列"></a>队列</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>225</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ImplementStackUsingQueues.md">用队列实现栈</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/queue/ImplementStackUsingQueues.java">Java</a></td><td><code>栈</code> <code>设计</code> <code>队列</code></td><td>简单</td></tr></tbody></table><h2 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>155</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MinStack.md">最小栈</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/stack/MinStack.java">Java</a></td><td><code>栈</code> <code>设计</code></td><td>简单</td></tr><tr><td>232</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ImplementQueueUsingStacks.md">用栈实现队列</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/stack/ImplementQueueUsingStacks.java">Java</a></td><td><code>栈</code> <code>设计</code> <code>队列</code></td><td>简单</td></tr></tbody></table><h2 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>13</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RomanToInteger.md">罗马数字转整数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/RomanToInt.java">Java</a></td><td><code>哈希表</code> <code>数学</code> <code>字符串</code></td><td>简单</td></tr><tr><td>20</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ValidParentheses.md">有效的括号</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/ValidParentheses.java">Java</a></td><td><code>栈</code> <code>字符串</code></td><td>简单</td></tr><tr><td>28</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ImplementStrstr.md">实现 strStr()</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/ImplementStrstr.java">Java</a></td><td><code>双指针</code> <code>字符串</code> <code>字符串匹配</code></td><td>简单</td></tr><tr><td>58</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/LengthOfLastWord.md">最后一个单词的长度</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/LengthOfLastWord.java">Java</a></td><td><code>字符串</code></td><td>简单</td></tr><tr><td>67</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/AddBinary.md">二进制求和</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/AddBinary.java">Java</a></td><td><code>位运算</code> <code>数学</code> <code>字符串</code> <code>模拟</code></td><td>简单</td></tr><tr><td>125</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ValidPalindrome.md">验证回文串</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/ValidPalindrome.java">Java</a></td><td><code>双指针</code> <code>字符串</code></td><td>简单</td></tr><tr><td>168</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ExcelSheetColumnTitle.md">Excel 表列名称</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/ExcelSheetColumnTitle.java">Java</a></td><td><code>数学</code> <code>字符串</code></td><td>简单</td></tr><tr><td>171</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ExcelSheetColumnNumber.md">Excel 表列序号</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/ExcelSheetColumnNumber.java">Java</a></td><td><code>数学</code> <code>字符串</code></td><td>简单</td></tr><tr><td>205</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/IsomorphicStrings.md">同构字符串</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/IsomorphicStrings.java">Java</a></td><td><code>哈希表</code> <code>字符串</code></td><td>简单</td></tr><tr><td>242</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ValidAnagram.md">有效的字母异位词</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/ValidAnagram.java">Java</a></td><td><code>哈希表</code> <code>字符串</code> <code>排序</code></td><td>简单</td></tr><tr><td>257</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/BinaryTreePaths.md">二叉树的所有路径</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/BinaryTreePaths.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>字符串</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>290</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/WordPattern.md">单词规律</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/WordPattern.java">Java</a></td><td><code>哈希表</code> <code>字符串</code></td><td>简单</td></tr><tr><td>344</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/ReverseString.java">反转字符串</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/ReverseString.md">Java</a></td><td><code>递归</code> <code>双指针</code> <code>字符串</code></td><td>简单</td></tr><tr><td>387</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/FirstUniqueCharacterInAString.md">字符串中的第一个唯一字符</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/FirstUniqueCharacterInAString.java">Java</a></td><td><code>队列</code> <code>哈希表</code> <code>字符串</code> <code>计数</code></td><td>简单</td></tr><tr><td>389</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/FindTheDifference.md">找不同</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/FindTheDifference.java">Java</a></td><td><code>位运算</code> <code>哈希表</code> <code>字符串</code> <code>排序</code></td><td>简单</td></tr><tr><td>392</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/IsSubsequence.md">判断子序列</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/IsSubsequence.java">Java</a></td><td><code>双指针</code> <code>字符串</code> <code>动态规划</code></td><td>简单</td></tr><tr><td>409</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/LongestPalindrome.md">最长回文串</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/LongestPalindrome.java">Java</a></td><td><code>贪心</code> <code>哈希表</code> <code>字符串</code></td><td>简单</td></tr><tr><td>434</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/NumberOfSegmentsInAString.md">字符串中的单词数</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/NumberOfSegmentsInAString.java">Java</a></td><td><code>字符串</code></td><td>简单</td></tr><tr><td>459</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/RepeatedSubstringPattern.md">重复的子字符串</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/string/RepeatedSubstringPattern.java">Java</a></td><td><code>字符串</code> <code>字符串匹配</code></td><td>简单</td></tr></tbody></table><h2 id="树"><a href="#树" class="headerlink" title="树"></a>树</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>94</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/BinaryTreeInorderTraversal.md">二叉树的中序遍历</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BinaryTreeInorderTraversal.java">Java</a></td><td><code>栈</code> <code>树</code> <code>深度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>100</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/SameTree.md">相同的树</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/SameTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>广度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>101</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/SymmetricTree.md">对称二叉树</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/SymmetricTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>广度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>104</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MaximumDepthOfBinaryTree.md">二叉树的最大深度</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/MaximumDepthOfBinaryTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>广度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>110</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/BalancedBinaryTree.md">平衡二叉树</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BalancedBinaryTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>111</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/MinimumDepthOfBinaryTree.md">二叉树的最小深度</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/MinimumDepthOfBinaryTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>广度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>112</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/PathSum.md">路径总和</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/PathSum.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>144</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/BinaryTreePreorderTraversal.md">二叉树的前序遍历</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BinaryTreePreorderTraversal.java">Java</a></td><td><code>栈</code> <code>树</code> <code>深度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>145</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/BinaryTreePostorderTraversal.md">二叉树的后序遍历</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/BinaryTreePostorderTraversal.java">Java</a></td><td><code>栈</code> <code>树</code> <code>深度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>226</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/InvertBinaryTree.md">翻转二叉树</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/InvertBinaryTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>广度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>235</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/LowestCommonAncestorOfABinarySearchTree.md">二叉搜索树的最近公共祖先</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/LowestCommonAncestorOfABinarySearchTree.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>二叉搜索树</code> <code>二叉树</code></td><td>简单</td></tr><tr><td>404</td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/docs/SumOfLeftLeaves.md">左叶子之和</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/java/com/leetcode/editor/tree/SumOfLeftLeaves.java">Java</a></td><td><code>树</code> <code>深度优先搜索</code> <code>广度优先搜索</code> <code>二叉树</code></td><td>简单</td></tr></tbody></table><h2 id="数据库"><a href="#数据库" class="headerlink" title="数据库"></a>数据库</h2><table><thead><tr><th>序号</th><th>题目</th><th>题解</th><th>标签</th><th>难度</th></tr></thead><tbody><tr><td>175</td><td><a href="https://leetcode.cn/problems/combine-two-tables/">组合两个表</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/CombineTwoTables.sql">MySQL</a></td><td><code>数据库</code></td><td>简单</td></tr><tr><td>176</td><td><a href="https://leetcode.cn/problems/second-highest-salary/">第二高的薪水</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/NthHighestSalary.sql">MySQL</a></td><td><code>数据库</code></td><td>中等</td></tr><tr><td>177</td><td><a href="https://leetcode.cn/problems/nth-highest-salary/">第N高的薪水</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/SecondHighestSalary.sql">MySQL</a></td><td><code>数据库</code></td><td>中等</td></tr><tr><td>181</td><td><a href="https://leetcode.cn/problems/employees-earning-more-than-their-managers/">超过经理收入的员工</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/EmployeesEarningMoreThanTheirManagers.sql">MySQL</a></td><td><code>数据库</code></td><td>简单</td></tr><tr><td>182</td><td><a href="https://leetcode.cn/problems/duplicate-emails/">查找重复的电子邮箱</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/DuplicateEmails.sql">MySQL</a></td><td><code>数据库</code></td><td>简单</td></tr><tr><td>183</td><td><a href="https://leetcode.cn/problems/customers-who-never-order/">从不订购的客户</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/CustomersWhoNeverOrder.sql">MySQL</a></td><td><code>数据库</code></td><td>简单</td></tr><tr><td>184</td><td><a href="https://leetcode.cn/problems/department-highest-salary/">部门工资最高的员工</a></td><td><a href="https://github.com/loquy/leetcode/blob/main/src/main/resources/sql/DepartmentHighestSalary.sql">MySQL</a></td><td><code>数据库</code></td><td>中等</td></tr></tbody></table>]]></content>
    
    
    <summary type="html">记录在 LeetCode 上学习的算法和数据结构，持续更新...</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="算法" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/%E7%AE%97%E6%B3%95/"/>
    
    <category term="数据结构" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    
    <category term="算法" scheme="http://www.loquy.cn/tags/%E7%AE%97%E6%B3%95/"/>
    
    <category term="数据结构" scheme="http://www.loquy.cn/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    <category term="LeetCode" scheme="http://www.loquy.cn/tags/LeetCode/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot 中使用 Mybatis</title>
    <link href="http://www.loquy.cn/posts/d45b7e43.html"/>
    <id>http://www.loquy.cn/posts/d45b7e43.html</id>
    <published>2022-06-14T02:42:48.000Z</published>
    <updated>2022-06-14T02:42:48.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><pre><code class="hljs">MyBatis 是一款优秀的持久层框架，它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO（Plain Old Java Objects，普通老式 Java 对象）为数据库中的记录。</code></pre><p>详细使用教程参见 <a href="https://mybatis.net.cn/">官方文档</a> 。</p><h1 id="表结构"><a href="#表结构" class="headerlink" title="表结构"></a>表结构</h1><p>创建名为 mybatis 数据库，执行以下 sql 语句创建 user 表。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `<span class="hljs-keyword">user</span>` (<br>  `id` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `name` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `pwd` <span class="hljs-type">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)<br>) ENGINE<span class="hljs-operator">=</span>MyISAM <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;<br></code></pre></td></tr></table></figure><h1 id="Maven-项目结构"><a href="#Maven-项目结构" class="headerlink" title="Maven 项目结构"></a>Maven 项目结构</h1><p><img src="https://www.loquy.cn/images/springboot-05-mybatis.jpg"></p><pre><code class="hljs">springboot-05-mybatis├─src│  ├─main│  │  ├─java│  │  │  └─com│  │  │      └─example│  │  │          │  Springboot05MybatisApplication.java│  │  │          ││  │  │          ├─controller│  │  │          │      UserController.java│  │  │          ││  │  │          ├─mapper│  │  │          │      UserMapper.java│  │  │          ││  │  │          └─pojo│  │  │                  User.java│  │  ││  │  └─resources│  │      │  application.properties│  │      ││  │      └─mybatis│  │          └─mapper│  │                  UserMapper.xml│  ││  └─test│      └─java│          └─com│              └─example│                      Springboot05MybatisApplicationTests.java</code></pre><h1 id="Pom-xml-依赖配置"><a href="#Pom-xml-依赖配置" class="headerlink" title="Pom.xml 依赖配置"></a>Pom.xml 依赖配置</h1><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.5.5<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springboot-05-mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>springboot-05-mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>Demo project for Spring Boot<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mybatis.spring.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis-spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.1.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br><br></code></pre></td></tr></table></figure><h1 id="Application-properties-配置"><a href="#Application-properties-配置" class="headerlink" title="Application.properties 配置"></a>Application.properties 配置</h1><ul><li><strong>mybatis.type-aliases-package：</strong> 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置，意在降低冗余的全限定类名书写。</li><li><strong>mybatis.mapper-locations：</strong> xml 映射器的位置，*.xml 代表目录下所有的 xml 文件</li></ul><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">spring.datasource.username</span>=<span class="hljs-string">root</span><br><span class="hljs-attr">spring.datasource.password</span>=<span class="hljs-string">root</span><br><span class="hljs-attr">spring.datasource.url</span>=<span class="hljs-string">jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&amp;setUnicode=true&amp;charterEncoding=utf-8</span><br><span class="hljs-attr">spring.datasource.driver-class-name</span>=<span class="hljs-string">com.mysql.cj.jdbc.Driver</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">#整合mybatis</span><br><span class="hljs-attr">mybatis.type-aliases-package</span>=<span class="hljs-string">com.example.pojo</span><br><span class="hljs-attr">mybatis.mapper-locations</span>=<span class="hljs-string">classpath:mybatis/mapper/*.xml</span><br></code></pre></td></tr></table></figure><h1 id="POJO-对象"><a href="#POJO-对象" class="headerlink" title="POJO 对象"></a>POJO 对象</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.pojo;<br><br><span class="hljs-keyword">import</span> lombok.AllArgsConstructor;<br><span class="hljs-keyword">import</span> lombok.Data;<br><span class="hljs-keyword">import</span> lombok.NoArgsConstructor;<br><br><span class="hljs-meta">@Data</span><br><span class="hljs-meta">@NoArgsConstructor</span><br><span class="hljs-meta">@AllArgsConstructor</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> id;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> String pwd;<br><br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="XML-映射器"><a href="#XML-映射器" class="headerlink" title="XML 映射器"></a>XML 映射器</h1><ul><li>在对应的标签中添加 sql 语句。</li><li>mapper 标签的 namespace 属性值为映射的接口类路径。</li><li>select、insert、update、delete 标签的 id 属性值为接口类下的方法，resultType 属性值为返回的对象类型。</li><li>标签详细的属性含义 <a href="https://mybatis.net.cn/sqlmap-xml.html">参见此处</a> 。</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span> ?&gt;</span><br><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">mapper</span></span><br><span class="hljs-meta">        <span class="hljs-keyword">PUBLIC</span> <span class="hljs-string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span></span><br><span class="hljs-meta">        <span class="hljs-string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mapper</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">&quot;com.example.mapper.UserMapper&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;queryUserList&quot;</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">&quot;User&quot;</span>&gt;</span><br>        select * from user<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;queryUserById&quot;</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">&quot;User&quot;</span>&gt;</span><br>        select * from user where id = #&#123;id&#125;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">insert</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;addUser&quot;</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">&quot;User&quot;</span>&gt;</span><br>        insert into user(id, name, pwd) values (#&#123;id&#125;, #&#123;name&#125;, #&#123;pwd&#125;)<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">insert</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">update</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;updateUser&quot;</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">&quot;User&quot;</span>&gt;</span><br>        update user set name=#&#123;name&#125;,pwd=#&#123;pwd&#125; where id = #&#123;id&#125;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">update</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">delete</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;deleteUser&quot;</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">&quot;int&quot;</span>&gt;</span><br>        delete from user where id = #&#123;id&#125;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">delete</span>&gt;</span><br><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">mapper</span>&gt;</span><br></code></pre></td></tr></table></figure><h1 id="接口类"><a href="#接口类" class="headerlink" title="接口类"></a>接口类</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.mapper;<br><br><span class="hljs-keyword">import</span> com.example.pojo.User;<br><span class="hljs-keyword">import</span> org.apache.ibatis.annotations.Mapper;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Repository;<br><br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-meta">@Mapper</span><br><span class="hljs-meta">@Repository</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserMapper</span> &#123;<br>    List&lt;User&gt; <span class="hljs-title function_">queryUserList</span><span class="hljs-params">()</span>;<br><br>    User <span class="hljs-title function_">queryUserById</span><span class="hljs-params">(<span class="hljs-type">int</span> id)</span>;<br><br>    <span class="hljs-type">int</span> <span class="hljs-title function_">addUser</span><span class="hljs-params">(User user)</span>;<br><br>    <span class="hljs-type">int</span> <span class="hljs-title function_">updateUser</span><span class="hljs-params">(User user)</span>;<br><br>    <span class="hljs-type">int</span> <span class="hljs-title function_">deleteUser</span><span class="hljs-params">(<span class="hljs-type">int</span> id)</span>;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><ul><li>新建控制器，添加 REST 请求接口。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.controller;<br><br><span class="hljs-keyword">import</span> com.example.mapper.UserMapper;<br><span class="hljs-keyword">import</span> com.example.pojo.User;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;<br><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;<br><br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-meta">@RestController</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserController</span> &#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> UserMapper userMapper;<br><br>    <span class="hljs-meta">@GetMapping(&quot;/queryUserList&quot;)</span><br>    <span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title function_">queryUserList</span><span class="hljs-params">()</span>&#123;<br>        List&lt;User&gt; userList = userMapper.queryUserList();<br>        <span class="hljs-keyword">for</span> (User user : userList) &#123;<br>            System.out.println(user);<br>        &#125;<br>        <span class="hljs-keyword">return</span> userList;<br>    &#125;<br><br>    <span class="hljs-meta">@GetMapping(&quot;/addUser&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">addUser</span><span class="hljs-params">()</span>&#123;<br>        userMapper.addUser(<span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>(<span class="hljs-number">5</span>, <span class="hljs-string">&quot;啊啊&quot;</span>, <span class="hljs-string">&quot;123123&quot;</span>));<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;ok&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@GetMapping(&quot;/updateUser&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">updateUser</span><span class="hljs-params">()</span>&#123;<br>        userMapper.updateUser(<span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>(<span class="hljs-number">5</span>, <span class="hljs-string">&quot;AA&quot;</span>, <span class="hljs-string">&quot;123123&quot;</span>));<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;ok&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@GetMapping(&quot;/deleteUser&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">deleteUser</span><span class="hljs-params">()</span>&#123;<br>        userMapper.deleteUser(<span class="hljs-number">5</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;ok&quot;</span>;<br>    &#125;<br><br>&#125;<br><br></code></pre></td></tr></table></figure><ul><li>请求结果。</li></ul><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">[</span><br>  <span class="hljs-punctuation">&#123;</span><br>    <span class="hljs-attr">&quot;id&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">5</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;AA&quot;</span><span class="hljs-punctuation">,</span><br>    <span class="hljs-attr">&quot;pwd&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;123123&quot;</span><br>  <span class="hljs-punctuation">&#125;</span><br><span class="hljs-punctuation">]</span><br></code></pre></td></tr></table></figure><p><img src="https://www.loquy.cn/images/queryUserList.jpg"></p><h1 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h1><p><a href="https://github.com/loquy/spring-boot/tree/main/springboot-05-mybatis">参见此仓库</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;MyBatis 是一款优秀的持久层框架，它支持自定义 SQL、存储过程以及高级映射。MyBatis</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="Mybatis" scheme="http://www.loquy.cn/tags/Mybatis/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot 中使用 Redis</title>
    <link href="http://www.loquy.cn/posts/54e4e761.html"/>
    <id>http://www.loquy.cn/posts/54e4e761.html</id>
    <published>2022-06-13T08:06:27.000Z</published>
    <updated>2022-06-13T08:06:27.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><pre><code class="hljs">Redis（Remote Dictionary Server )，即远程字典服务，是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库，并提供多种语言的API。</code></pre><ul><li><p>最新版本的 Redis 文件可在 <a href="https://github.com/redis/redis/releases">GitHub Releases</a> 上获得。</p></li><li><p>首先要启动 redis-server，<a href="https://www.runoob.com/redis/redis-tutorial.html">教程参见此处</a> 。</p></li></ul><h1 id="Maven-项目结构"><a href="#Maven-项目结构" class="headerlink" title="Maven 项目结构"></a>Maven 项目结构</h1><p><img src="https://www.loquy.cn/images/springboot-10-redis.jpg"></p><pre><code class="hljs">springboot-10-redis├─src│  ├─main│  │  ├─java│  │  │  └─com│  │  │      └─example│  │  │          │  Springboot10RedisApplication.java│  │  │          ││  │  │          ├─config│  │  │          │      RedisConfig.java│  │  │          ││  │  │          ├─pojo│  │  │          │      User.java│  │  │          ││  │  │          └─utils│  │  │                  RedisUtil.java│  │  ││  │  └─resources│  │          application.properties│  ││  └─test│      └─java│          └─com│              └─example│                      Springboot10RedisApplicationTests.java</code></pre><h1 id="Pom-xml-依赖配置"><a href="#Pom-xml-依赖配置" class="headerlink" title="Pom.xml 依赖配置"></a>Pom.xml 依赖配置</h1><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.5.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springboot-10-redis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>springboot-10-redis<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>Demo project for Spring Boot<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-devtools<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">optional</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">optional</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">optional</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">optional</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">optional</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">optional</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">excludes</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">exclude</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">exclude</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">excludes</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br><br></code></pre></td></tr></table></figure><h1 id="Redis-配置"><a href="#Redis-配置" class="headerlink" title="Redis 配置"></a>Redis 配置</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.config;<br><br><span class="hljs-keyword">import</span> com.fasterxml.jackson.annotation.JsonAutoDetect;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.annotation.PropertyAccessor;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;<br><span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;<br><span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;<br><span class="hljs-keyword">import</span> org.springframework.data.redis.connection.RedisConnectionFactory;<br><span class="hljs-keyword">import</span> org.springframework.data.redis.core.RedisTemplate;<br><span class="hljs-keyword">import</span> org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;<br><span class="hljs-keyword">import</span> org.springframework.data.redis.serializer.StringRedisSerializer;<br><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">RedisConfig</span> &#123;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-meta">@ConditionalOnMissingBean(</span><br><span class="hljs-meta">            name = &#123;&quot;redisTemplate&quot;&#125;</span><br><span class="hljs-meta">    )</span><br>    <span class="hljs-meta">@ConditionalOnSingleCandidate(RedisConnectionFactory.class)</span><br>    <span class="hljs-keyword">public</span> RedisTemplate&lt;String, Object&gt; <span class="hljs-title function_">redisTemplate</span><span class="hljs-params">(RedisConnectionFactory factory)</span> &#123;<br>        RedisTemplate&lt;String, Object&gt; template = <span class="hljs-keyword">new</span> <span class="hljs-title class_">RedisTemplate</span>&lt;&gt;();<br>        template.setConnectionFactory(factory);<br><br>        <span class="hljs-comment">// json 序列化配置</span><br>        Jackson2JsonRedisSerializer&lt;Object&gt; Jackson2JsonRedisSerializer = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Jackson2JsonRedisSerializer</span>&lt;&gt;(Object.class);<br>        <span class="hljs-type">ObjectMapper</span> <span class="hljs-variable">om</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectMapper</span>();<br>        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);<br>        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);<br>        Jackson2JsonRedisSerializer.setObjectMapper(om);<br><br>        <span class="hljs-comment">// String 的序列化</span><br>        <span class="hljs-type">StringRedisSerializer</span> <span class="hljs-variable">stringRedisSerializer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringRedisSerializer</span>();<br><br>        template.setKeySerializer(stringRedisSerializer);<br>        template.setHashKeySerializer(stringRedisSerializer);<br>        template.setValueSerializer(Jackson2JsonRedisSerializer);<br>        template.setHashValueSerializer(Jackson2JsonRedisSerializer);<br>        template.afterPropertiesSet();<br><br>        <span class="hljs-keyword">return</span> template;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="Application-properties-配置"><a href="#Application-properties-配置" class="headerlink" title="Application.properties 配置"></a>Application.properties 配置</h1><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-comment">#=====================redis ========</span><br><span class="hljs-comment"># Redis服务器地址</span><br><span class="hljs-attr">spring.redis.host</span>=<span class="hljs-string">localhost</span><br><span class="hljs-comment"># Redis服务器连接端口</span><br><span class="hljs-attr">spring.redis.port</span>=<span class="hljs-string">6379</span><br></code></pre></td></tr></table></figure><h1 id="Redis-工具类"><a href="#Redis-工具类" class="headerlink" title="Redis 工具类"></a>Redis 工具类</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.utils;<br><br><span class="hljs-keyword">import</span> java.util.Collection;<br><span class="hljs-keyword">import</span> java.util.List;<br><span class="hljs-keyword">import</span> java.util.Map;<br><span class="hljs-keyword">import</span> java.util.Set;<br><span class="hljs-keyword">import</span> java.util.concurrent.TimeUnit;<br><br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.data.redis.core.RedisTemplate;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><span class="hljs-keyword">import</span> org.springframework.util.CollectionUtils;<br><br><span class="hljs-keyword">import</span> lombok.extern.slf4j.Slf4j;<br><br><br><span class="hljs-meta">@Component</span><br><span class="hljs-meta">@Slf4j</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">RedisUtil</span> &#123;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> RedisTemplate redisTemplate;<br><br>    <span class="hljs-comment">// =============================common============================</span><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 指定缓存失效时间</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time 时间(秒)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">expire</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> time)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>) &#123;<br>                redisTemplate.expire(key, time, TimeUnit.SECONDS);<br>            &#125;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 根据key 获取过期时间</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键 不能为null</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 时间(秒) 返回0代表为永久有效</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">getExpire</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">return</span> redisTemplate.getExpire(key, TimeUnit.SECONDS);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 判断key是否存在</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 存在 false不存在</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">hasKey</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.hasKey(key);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 删除缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 可以传一个值 或多个</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@SuppressWarnings(&quot;unchecked&quot;)</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">del</span><span class="hljs-params">(String... key)</span> &#123;<br>        <span class="hljs-keyword">if</span> (key != <span class="hljs-literal">null</span> &amp;&amp; key.length &gt; <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">if</span> (key.length == <span class="hljs-number">1</span>) &#123;<br>                redisTemplate.delete(key[<span class="hljs-number">0</span>]);<br>            &#125; <span class="hljs-keyword">else</span> &#123;<br>                redisTemplate.delete((Collection&lt;String&gt;) CollectionUtils.arrayToList(key));<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">// ============================String=============================</span><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 普通缓存获取</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 值</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Object <span class="hljs-title function_">get</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">return</span> key == <span class="hljs-literal">null</span> ? <span class="hljs-literal">null</span> : redisTemplate.opsForValue().get(key);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 普通缓存放入</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true成功 false失败</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">set</span><span class="hljs-params">(String key, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForValue().set(key, value);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br><br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 普通缓存放入并设置时间</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time  时间(秒) time要大于0 如果time小于等于0 将设置无限期</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true成功 false 失败</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">set</span><span class="hljs-params">(String key, Object value, <span class="hljs-type">long</span> time)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>) &#123;<br>                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);<br>            &#125; <span class="hljs-keyword">else</span> &#123;<br>                set(key, value);<br>            &#125;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 递增 适用场景： https://blog.csdn.net/y_y_y_k_k_k_k/article/details/79218254 高并发生成订单号，秒杀类的业务逻辑等。。</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> delta 要增加几(大于0)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">incr</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> delta)</span> &#123;<br>        <span class="hljs-keyword">if</span> (delta &lt; <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(<span class="hljs-string">&quot;递增因子必须大于0&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForValue().increment(key, delta);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 递减</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> delta 要减少几(小于0)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">decr</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> delta)</span> &#123;<br>        <span class="hljs-keyword">if</span> (delta &lt; <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(<span class="hljs-string">&quot;递减因子必须大于0&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForValue().increment(key, -delta);<br>    &#125;<br><br>    <span class="hljs-comment">// ================================Map=================================</span><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * HashGet</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键 不能为null</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item 项 不能为null</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 值</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Object <span class="hljs-title function_">hget</span><span class="hljs-params">(String key, String item)</span> &#123;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForHash().get(key, item);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取hashKey对应的所有键值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 对应的多个键值</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Map&lt;Object, Object&gt; <span class="hljs-title function_">hmget</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForHash().entries(key);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * HashSet</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> map 对应多个键值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 成功 false 失败</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">hmset</span><span class="hljs-params">(String key, Map&lt;String, Object&gt; map)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForHash().putAll(key, map);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * HashSet 并设置时间</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> map  对应多个键值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time 时间(秒)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true成功 false失败</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">hmset</span><span class="hljs-params">(String key, Map&lt;String, Object&gt; map, <span class="hljs-type">long</span> time)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForHash().putAll(key, map);<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>) &#123;<br>                expire(key, time);<br>            &#125;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 向一张hash表中放入数据,如果不存在将创建</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item  项</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 成功 false失败</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">hset</span><span class="hljs-params">(String key, String item, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForHash().put(key, item, value);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 向一张hash表中放入数据,如果不存在将创建</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item  项</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 成功 false失败</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">hset</span><span class="hljs-params">(String key, String item, Object value, <span class="hljs-type">long</span> time)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForHash().put(key, item, value);<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>) &#123;<br>                expire(key, time);<br>            &#125;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 删除hash表中的值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键 不能为null</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item 项 可以使多个 不能为null</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">hdel</span><span class="hljs-params">(String key, Object... item)</span> &#123;<br>        redisTemplate.opsForHash().delete(key, item);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 判断hash表中是否有该项的值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键 不能为null</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item 项 不能为null</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 存在 false不存在</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">hHasKey</span><span class="hljs-params">(String key, String item)</span> &#123;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForHash().hasKey(key, item);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * hash递增 如果不存在,就会创建一个 并把新增后的值返回</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item 项</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> by   要增加几(大于0)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">double</span> <span class="hljs-title function_">hincr</span><span class="hljs-params">(String key, String item, <span class="hljs-type">double</span> by)</span> &#123;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForHash().increment(key, item, by);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * hash递减</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key  键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> item 项</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> by   要减少记(小于0)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">double</span> <span class="hljs-title function_">hdecr</span><span class="hljs-params">(String key, String item, <span class="hljs-type">double</span> by)</span> &#123;<br>        <span class="hljs-keyword">return</span> redisTemplate.opsForHash().increment(key, item, -by);<br>    &#125;<br><br>    <span class="hljs-comment">// ============================set=============================</span><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 根据key获取Set中的所有值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Set&lt;Object&gt; <span class="hljs-title function_">sGet</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().members(key);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 根据value从一个set中查询,是否存在</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 存在 false不存在</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">sHasKey</span><span class="hljs-params">(String key, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().isMember(key, value);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将数据放入set缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key    键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> values 值 可以是多个</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 成功个数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">sSet</span><span class="hljs-params">(String key, Object... values)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().add(key, values);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将set数据放入缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key    键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time   时间(秒)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> values 值 可以是多个</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 成功个数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">sSetAndTime</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> time, Object... values)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Long</span> <span class="hljs-variable">count</span> <span class="hljs-operator">=</span> redisTemplate.opsForSet().add(key, values);<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>)<br>                expire(key, time);<br>            <span class="hljs-keyword">return</span> count;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取set缓存的长度</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">sGetSetSize</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().size(key);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 移除值为value的</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key    键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> values 值 可以是多个</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 移除的个数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">setRemove</span><span class="hljs-params">(String key, Object... values)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Long</span> <span class="hljs-variable">count</span> <span class="hljs-operator">=</span> redisTemplate.opsForSet().remove(key, values);<br>            <span class="hljs-keyword">return</span> count;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">// ============================zset=============================</span><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 根据key获取Set中的所有值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Set&lt;Object&gt; <span class="hljs-title function_">zSGet</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().members(key);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 根据value从一个set中查询,是否存在</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> true 存在 false不存在</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">zSHasKey</span><span class="hljs-params">(String key, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().isMember(key, value);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> Boolean <span class="hljs-title function_">zSSet</span><span class="hljs-params">(String key, Object value, <span class="hljs-type">double</span> score)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForZSet().add(key, value, <span class="hljs-number">2</span>);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将set数据放入缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key    键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time   时间(秒)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> values 值 可以是多个</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 成功个数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">zSSetAndTime</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> time, Object... values)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Long</span> <span class="hljs-variable">count</span> <span class="hljs-operator">=</span> redisTemplate.opsForSet().add(key, values);<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>)<br>                expire(key, time);<br>            <span class="hljs-keyword">return</span> count;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取set缓存的长度</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">zSGetSetSize</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForSet().size(key);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 移除值为value的</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key    键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> values 值 可以是多个</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 移除的个数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">zSetRemove</span><span class="hljs-params">(String key, Object... values)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Long</span> <span class="hljs-variable">count</span> <span class="hljs-operator">=</span> redisTemplate.opsForSet().remove(key, values);<br>            <span class="hljs-keyword">return</span> count;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br>    <span class="hljs-comment">// ===============================list=================================</span><br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取list缓存的内容</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> start 开始 0 是第一个元素</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> end   结束 -1代表所有值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     * @取出来的元素 总数 end-start+1</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> List&lt;Object&gt; <span class="hljs-title function_">lGet</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> start, <span class="hljs-type">long</span> end)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForList().range(key, start, end);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取list缓存的长度</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key 键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">lGetListSize</span><span class="hljs-params">(String key)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForList().size(key);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 通过索引 获取list中的值</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> index 索引 index&gt;=0时， 0 表头，1 第二个元素，依次类推；index&lt;0时，-1，表尾，-2倒数第二个元素，依次类推</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> Object <span class="hljs-title function_">lGetIndex</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> index)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> redisTemplate.opsForList().index(key, index);<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将list放入缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">lSet</span><span class="hljs-params">(String key, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForList().rightPush(key, value);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将list放入缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time  时间(秒)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">lSet</span><span class="hljs-params">(String key, Object value, <span class="hljs-type">long</span> time)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForList().rightPush(key, value);<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>)<br>                expire(key, time);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将list放入缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">lSet</span><span class="hljs-params">(String key, List&lt;Object&gt; value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForList().rightPushAll(key, value);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 将list放入缓存</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> time  时间(秒)</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">lSet</span><span class="hljs-params">(String key, List&lt;Object&gt; value, <span class="hljs-type">long</span> time)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForList().rightPushAll(key, value);<br>            <span class="hljs-keyword">if</span> (time &gt; <span class="hljs-number">0</span>)<br>                expire(key, time);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 根据索引修改list中的某条数据</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> index 索引</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">lUpdateIndex</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> index, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            redisTemplate.opsForList().set(key, index, value);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 移除N个值为value</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> key   键</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> count 移除多少个</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> value 值</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 移除的个数</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">long</span> <span class="hljs-title function_">lRemove</span><span class="hljs-params">(String key, <span class="hljs-type">long</span> count, Object value)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Long</span> <span class="hljs-variable">remove</span> <span class="hljs-operator">=</span> redisTemplate.opsForList().remove(key, count, value);<br>            <span class="hljs-keyword">return</span> remove;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            log.error(key, e);<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>        &#125;<br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure><h1 id="POJO-对象"><a href="#POJO-对象" class="headerlink" title="POJO 对象"></a>POJO 对象</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.pojo;<br><br><span class="hljs-keyword">import</span> lombok.AllArgsConstructor;<br><span class="hljs-keyword">import</span> lombok.Data;<br><span class="hljs-keyword">import</span> lombok.NoArgsConstructor;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><br><span class="hljs-meta">@Component</span><br><span class="hljs-meta">@AllArgsConstructor</span><br><span class="hljs-meta">@NoArgsConstructor</span><br><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> &#123;<br><br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> age;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="Junit-测试"><a href="#Junit-测试" class="headerlink" title="Junit 测试"></a>Junit 测试</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example;<br><br><span class="hljs-keyword">import</span> com.example.pojo.User;<br><span class="hljs-keyword">import</span> com.example.utils.RedisUtil;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.core.JsonProcessingException;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;<br><span class="hljs-keyword">import</span> org.junit.jupiter.api.Test;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.boot.test.context.SpringBootTest;<br><span class="hljs-keyword">import</span> org.springframework.data.redis.core.RedisTemplate;<br><br><span class="hljs-meta">@SpringBootTest</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Springboot10RedisApplicationTests</span> &#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> RedisTemplate redisTemplate;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> RedisUtil redisUtil;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test1</span><span class="hljs-params">()</span>&#123;<br>        redisUtil.set(<span class="hljs-string">&quot;name&quot;</span>, <span class="hljs-string">&quot;test3&quot;</span>);<br>        System.out.println(redisUtil.get(<span class="hljs-string">&quot;name&quot;</span>));<br>    &#125;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">void</span> <span class="hljs-title function_">contextLoads</span><span class="hljs-params">()</span> &#123;<br><br>        redisTemplate.opsForValue().set(<span class="hljs-string">&quot;k1&quot;</span>, <span class="hljs-string">&quot;v1&quot;</span>);<br><br>        System.out.println(redisTemplate.opsForValue().get(<span class="hljs-string">&quot;k1&quot;</span>));<br>    &#125;<br><br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> JsonProcessingException &#123;<br><br>        <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>(<span class="hljs-string">&quot;user&quot;</span>, <span class="hljs-number">11</span>);<br><br>        <span class="hljs-type">String</span> <span class="hljs-variable">joinUser</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectMapper</span>().writeValueAsString(user);<br><br>        redisTemplate.opsForValue().set(<span class="hljs-string">&quot;user&quot;</span>, joinUser);<br><br>        System.out.println(redisTemplate.opsForValue().get(<span class="hljs-string">&quot;user&quot;</span>));<br>    &#125;<br><br>&#125;<br><br></code></pre></td></tr></table></figure><p><img src="https://www.loquy.cn/images/Springboot10RedisApplicationTests.jpg"></p><h1 id="项目源码"><a href="#项目源码" class="headerlink" title="项目源码"></a>项目源码</h1><p><a href="https://github.com/loquy/spring-boot/tree/main/springboot-10-redis">参见此仓库</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Redis（Remote Dictionary Server )，即远程字典服务，是一个开源的使用</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
    <category term="SpringBoot" scheme="http://www.loquy.cn/tags/SpringBoot/"/>
    
    <category term="Redis" scheme="http://www.loquy.cn/tags/Redis/"/>
    
  </entry>
  
  <entry>
    <title>JavaScript 常用业务代码总结</title>
    <link href="http://www.loquy.cn/posts/9296f96c.html"/>
    <id>http://www.loquy.cn/posts/9296f96c.html</id>
    <published>2022-06-10T03:13:52.000Z</published>
    <updated>2022-06-29T03:35:52.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="事件和选择器"><a href="#事件和选择器" class="headerlink" title="事件和选择器"></a>事件和选择器</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 元素选择器</span><br>$(<span class="hljs-string">&quot;p&quot;</span>)<br><span class="hljs-comment">// #id 选择器</span><br>$(<span class="hljs-string">&quot;#test&quot;</span>)<br><span class="hljs-comment">// .class 选择器</span><br>$(<span class="hljs-string">&quot;.test&quot;</span>)<br><br></code></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 点击事件</span><br>$(<span class="hljs-string">&quot;p&quot;</span>).<span class="hljs-title function_">click</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>    <span class="hljs-comment">// 动作触发后执行的代码!!</span><br>&#125;);<br><span class="hljs-comment">// 添加一个或多个事件处理程序</span><br>$(<span class="hljs-string">&quot;p&quot;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&quot;click&quot;</span>,<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>    <span class="hljs-title function_">alert</span>(<span class="hljs-string">&quot;段落被点击了。&quot;</span>);<br>&#125;);<br></code></pre></td></tr></table></figure><p>$(<em>selector</em>).on(<em>event,childSelector,data,function</em>)</p><table><thead><tr><th align="left">参数</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><em>event</em></td><td align="left">必需。规定要从被选元素添加的一个或多个事件或命名空间。  由空格分隔多个事件值，也可以是数组。必须是有效的事件。</td></tr><tr><td align="left"><em>childSelector</em></td><td align="left">可选。规定只能添加到指定的子元素上的事件处理程序（且不是选择器本身，比如已废弃的 delegate() 方法）。</td></tr><tr><td align="left"><em>data</em></td><td align="left">可选。规定传递到函数的额外数据。</td></tr><tr><td align="left"><em>function</em></td><td align="left">可选。规定当事件发生时运行的函数。</td></tr></tbody></table><h1 id="Ajax-执行异步的-HTTP-请求方法"><a href="#Ajax-执行异步的-HTTP-请求方法" class="headerlink" title="Ajax 执行异步的 HTTP 请求方法"></a>Ajax 执行异步的 HTTP 请求方法</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs javascript">$.<span class="hljs-title function_">ajax</span>(&#123;<br>    <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;get&quot;</span>,<br>    <span class="hljs-attr">async</span>: <span class="hljs-literal">true</span>,<br>    <span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span>,<br>    <span class="hljs-attr">dataType</span>: <span class="hljs-string">&quot;json&quot;</span>,<br>    <span class="hljs-attr">data</span>: &#123;&#125;,<br>    <span class="hljs-attr">contentType</span>: <span class="hljs-string">&quot;application/json;charset=UTF-8&quot;</span>,<br>    <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>) &#123;<br>    &#125;,<br>    <span class="hljs-attr">error</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">err</span>) &#123;<br>        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(err)<br>    &#125;,<br>    <span class="hljs-attr">complete</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>) &#123;<br>        <span class="hljs-title function_">reload</span>();<br>    &#125;<br>&#125;)<br></code></pre></td></tr></table></figure><p>下面的表格中列出了可能的名称&#x2F;值：</p><table><thead><tr><th align="left">名称</th><th align="left">值&#x2F;描述</th></tr></thead><tbody><tr><td align="left">async</td><td align="left">布尔值，表示请求是否异步处理。默认是 true。</td></tr><tr><td align="left">beforeSend(<em>xhr</em>)</td><td align="left">发送请求前运行的函数。</td></tr><tr><td align="left">cache</td><td align="left">布尔值，表示浏览器是否缓存被请求页面。默认是 true。</td></tr><tr><td align="left">complete(<em>xhr,status</em>)</td><td align="left">请求完成时运行的函数（在请求成功或失败之后均调用，即在 success 和 error 函数之后）。</td></tr><tr><td align="left">contentType</td><td align="left">发送数据到服务器时所使用的内容类型。默认是：”application&#x2F;x-www-form-urlencoded”。</td></tr><tr><td align="left">context</td><td align="left">为所有 AJAX 相关的回调函数规定 “this” 值。</td></tr><tr><td align="left">data</td><td align="left">规定要发送到服务器的数据。</td></tr><tr><td align="left">dataFilter(<em>data</em>,<em>type</em>)</td><td align="left">用于处理 XMLHttpRequest 原始响应数据的函数。</td></tr><tr><td align="left">dataType</td><td align="left">预期的服务器响应的数据类型。</td></tr><tr><td align="left">error(<em>xhr,status,error</em>)</td><td align="left">如果请求失败要运行的函数。</td></tr><tr><td align="left">global</td><td align="left">布尔值，规定是否为请求触发全局 AJAX 事件处理程序。默认是 true。</td></tr><tr><td align="left">ifModified</td><td align="left">布尔值，规定是否仅在最后一次请求以来响应发生改变时才请求成功。默认是 false。</td></tr><tr><td align="left">jsonp</td><td align="left">在一个 jsonp 中重写回调函数的字符串。</td></tr><tr><td align="left">jsonpCallback</td><td align="left">在一个 jsonp 中规定回调函数的名称。</td></tr><tr><td align="left">password</td><td align="left">规定在 HTTP 访问认证请求中使用的密码。</td></tr><tr><td align="left">processData</td><td align="left">布尔值，规定通过请求发送的数据是否转换为查询字符串。默认是 true。</td></tr><tr><td align="left">scriptCharset</td><td align="left">规定请求的字符集。</td></tr><tr><td align="left">success(<em>result,status,xhr</em>)</td><td align="left">当请求成功时运行的函数。</td></tr><tr><td align="left">timeout</td><td align="left">设置本地的请求超时时间（以毫秒计）。</td></tr><tr><td align="left">traditional</td><td align="left">布尔值，规定是否使用参数序列化的传统样式。</td></tr><tr><td align="left">type</td><td align="left">规定请求的类型（GET 或 POST）。</td></tr><tr><td align="left">url</td><td align="left">规定发送请求的 URL。默认是当前页面。</td></tr><tr><td align="left">username</td><td align="left">规定在 HTTP 访问认证请求中使用的用户名。</td></tr><tr><td align="left">xhr</td><td align="left">用于创建 XMLHttpRequest 对象的函数。</td></tr></tbody></table><h1 id="Layer-弹出层组件"><a href="#Layer-弹出层组件" class="headerlink" title="Layer 弹出层组件"></a>Layer 弹出层组件</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><code class="hljs javascript">特别说明：<br>事件需自己绑定，以下只展现调用代码。<br> <br><span class="hljs-comment">//初体验</span><br><br>layer.<span class="hljs-title function_">alert</span>(<span class="hljs-string">&#x27;内容&#x27;</span>)<br> <br><span class="hljs-comment">//询问框</span><br><br>layer.<span class="hljs-title function_">confirm</span>(<span class="hljs-string">&#x27;您是如何看待前端开发？&#x27;</span>, &#123;<br>  <span class="hljs-attr">btn</span>: [<span class="hljs-string">&#x27;重要&#x27;</span>,<span class="hljs-string">&#x27;奇葩&#x27;</span>] <span class="hljs-comment">//按钮</span><br>&#125;, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>  layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;的确很重要&#x27;</span>, &#123;<span class="hljs-attr">icon</span>: <span class="hljs-number">1</span>&#125;);<br>&#125;, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>  layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;也可以这样&#x27;</span>, &#123;<br>    <span class="hljs-attr">time</span>: <span class="hljs-number">20000</span>, <span class="hljs-comment">//20s后自动关闭</span><br>    <span class="hljs-attr">btn</span>: [<span class="hljs-string">&#x27;明白了&#x27;</span>, <span class="hljs-string">&#x27;知道了&#x27;</span>]<br>  &#125;);<br>&#125;);<br> <br><span class="hljs-comment">//提示层</span><br><br>layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;一段提示信息&#x27;</span>);<br> <br><span class="hljs-comment">//墨绿深蓝风</span><br><br>layer.<span class="hljs-title function_">alert</span>(<span class="hljs-string">&#x27;墨绿风格，点击确认看深蓝&#x27;</span>, &#123;<br>  <span class="hljs-attr">skin</span>: <span class="hljs-string">&#x27;layui-layer-molv&#x27;</span> <span class="hljs-comment">//样式类名</span><br>  ,<span class="hljs-attr">closeBtn</span>: <span class="hljs-number">0</span><br>&#125;, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>  layer.<span class="hljs-title function_">alert</span>(<span class="hljs-string">&#x27;偶吧深蓝style&#x27;</span>, &#123;<br>    <span class="hljs-attr">skin</span>: <span class="hljs-string">&#x27;layui-layer-lan&#x27;</span><br>    ,<span class="hljs-attr">closeBtn</span>: <span class="hljs-number">0</span><br>    ,<span class="hljs-attr">anim</span>: <span class="hljs-number">4</span> <span class="hljs-comment">//动画类型</span><br>  &#125;);<br>&#125;);<br><span class="hljs-comment">//捕获页</span><br><br>layer.<span class="hljs-title function_">open</span>(&#123;<br>  <span class="hljs-attr">type</span>: <span class="hljs-number">1</span>,<br>  <span class="hljs-attr">shade</span>: <span class="hljs-literal">false</span>,<br>  <span class="hljs-attr">title</span>: <span class="hljs-literal">false</span>, <span class="hljs-comment">//不显示标题</span><br>  <span class="hljs-attr">content</span>: $(<span class="hljs-string">&#x27;.layer_notice&#x27;</span>), <span class="hljs-comment">//捕获的元素，注意：最好该指定的元素要存放在body最外层，否则可能被其它的相对元素所影响</span><br>  <span class="hljs-attr">cancel</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>    layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;捕获就是从页面已经存在的元素上，包裹layer的结构&#x27;</span>, &#123;<span class="hljs-attr">time</span>: <span class="hljs-number">5000</span>, <span class="hljs-attr">icon</span>:<span class="hljs-number">6</span>&#125;);<br>  &#125;<br>&#125;);<br><span class="hljs-comment">//页面层</span><br><br>layer.<span class="hljs-title function_">open</span>(&#123;<br>  <span class="hljs-attr">type</span>: <span class="hljs-number">1</span>,<br>  <span class="hljs-attr">skin</span>: <span class="hljs-string">&#x27;layui-layer-rim&#x27;</span>, <span class="hljs-comment">//加上边框</span><br>  <span class="hljs-attr">area</span>: [<span class="hljs-string">&#x27;420px&#x27;</span>, <span class="hljs-string">&#x27;240px&#x27;</span>], <span class="hljs-comment">//宽高</span><br>  <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;html内容&#x27;</span><br>&#125;);<br><span class="hljs-comment">//自定页</span><br><br>layer.<span class="hljs-title function_">open</span>(&#123;<br>  <span class="hljs-attr">type</span>: <span class="hljs-number">1</span>,<br>  <span class="hljs-attr">skin</span>: <span class="hljs-string">&#x27;layui-layer-demo&#x27;</span>, <span class="hljs-comment">//样式类名</span><br>  <span class="hljs-attr">closeBtn</span>: <span class="hljs-number">0</span>, <span class="hljs-comment">//不显示关闭按钮</span><br>  <span class="hljs-attr">anim</span>: <span class="hljs-number">2</span>,<br>  <span class="hljs-attr">shadeClose</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//开启遮罩关闭</span><br>  <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;内容&#x27;</span><br>&#125;);<br><span class="hljs-comment">//tips层</span><br><br>layer.<span class="hljs-title function_">tips</span>(<span class="hljs-string">&#x27;Hi，我是tips&#x27;</span>, <span class="hljs-string">&#x27;吸附元素选择器，如#id&#x27;</span>);<br><span class="hljs-comment">//iframe 层</span><br><br>layer.<span class="hljs-title function_">open</span>(&#123;<br>  <span class="hljs-attr">type</span>: <span class="hljs-number">2</span>,<br>  <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;layer mobile页&#x27;</span>,<br>  <span class="hljs-attr">shadeClose</span>: <span class="hljs-literal">true</span>,<br>  <span class="hljs-attr">shade</span>: <span class="hljs-number">0.8</span>,<br>  <span class="hljs-attr">area</span>: [<span class="hljs-string">&#x27;380px&#x27;</span>, <span class="hljs-string">&#x27;90%&#x27;</span>],<br>  <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;mobile/&#x27;</span> <span class="hljs-comment">//iframe的url</span><br>&#125;); <br><span class="hljs-comment">//iframe 层</span><br><br>layer.<span class="hljs-title function_">open</span>(&#123;<br>  <span class="hljs-attr">type</span>: <span class="hljs-number">2</span>,<br>  <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;很多时候，我们想最大化看，比如像这个页面。&#x27;</span>,<br>  <span class="hljs-attr">shadeClose</span>: <span class="hljs-literal">true</span>,<br>  <span class="hljs-attr">shade</span>: <span class="hljs-literal">false</span>,<br>  <span class="hljs-attr">maxmin</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//开启最大化最小化按钮</span><br>  <span class="hljs-attr">area</span>: [<span class="hljs-string">&#x27;893px&#x27;</span>, <span class="hljs-string">&#x27;600px&#x27;</span>],<br>  <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;https://layui.jianwoo.cn&#x27;</span><br>&#125;);<br><span class="hljs-comment">//加载层</span><br><br><span class="hljs-keyword">var</span> index = layer.<span class="hljs-title function_">load</span>(<span class="hljs-number">0</span>, &#123;<span class="hljs-attr">shade</span>: <span class="hljs-literal">false</span>&#125;); <span class="hljs-comment">//0代表加载的风格，支持0-2</span><br><span class="hljs-comment">//loading层</span><br><br><span class="hljs-keyword">var</span> index = layer.<span class="hljs-title function_">load</span>(<span class="hljs-number">1</span>, &#123;<br>  <span class="hljs-attr">shade</span>: [<span class="hljs-number">0.1</span>,<span class="hljs-string">&#x27;#fff&#x27;</span>] <span class="hljs-comment">//0.1透明度的白色背景</span><br>&#125;);<br><span class="hljs-comment">//小tips</span><br><br>layer.<span class="hljs-title function_">tips</span>(<span class="hljs-string">&#x27;我是另外一个tips，只不过我长得跟之前那位稍有些不一样。&#x27;</span>, <span class="hljs-string">&#x27;吸附元素选择器&#x27;</span>, &#123;<br>  <span class="hljs-attr">tips</span>: [<span class="hljs-number">1</span>, <span class="hljs-string">&#x27;#3595CC&#x27;</span>],<br>  <span class="hljs-attr">time</span>: <span class="hljs-number">4000</span><br>&#125;);<br><span class="hljs-comment">//prompt层</span><br><br>layer.<span class="hljs-title function_">prompt</span>(&#123;<span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;输入任何口令，并确认&#x27;</span>, <span class="hljs-attr">formType</span>: <span class="hljs-number">1</span>&#125;, <span class="hljs-keyword">function</span>(<span class="hljs-params">pass, index</span>)&#123;<br>  layer.<span class="hljs-title function_">close</span>(index);<br>  layer.<span class="hljs-title function_">prompt</span>(&#123;<span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;随便写点啥，并确认&#x27;</span>, <span class="hljs-attr">formType</span>: <span class="hljs-number">2</span>&#125;, <span class="hljs-keyword">function</span>(<span class="hljs-params">text, index</span>)&#123;<br>    layer.<span class="hljs-title function_">close</span>(index);<br>    layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;演示完毕！您的口令：&#x27;</span>+ pass +<span class="hljs-string">&#x27;&lt;br&gt;您最后写下了：&#x27;</span>+text);<br>  &#125;);<br>&#125;);<br><span class="hljs-comment">//tab层</span><br><br>layer.<span class="hljs-title function_">tab</span>(&#123;<br>  <span class="hljs-attr">area</span>: [<span class="hljs-string">&#x27;600px&#x27;</span>, <span class="hljs-string">&#x27;300px&#x27;</span>],<br>  <span class="hljs-attr">tab</span>: [&#123;<br>    <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;TAB1&#x27;</span>, <br>    <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;内容1&#x27;</span><br>  &#125;, &#123;<br>    <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;TAB2&#x27;</span>, <br>    <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;内容2&#x27;</span><br>  &#125;, &#123;<br>    <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;TAB3&#x27;</span>, <br>    <span class="hljs-attr">content</span>: <span class="hljs-string">&#x27;内容3&#x27;</span><br>  &#125;]<br>&#125;);<br><span class="hljs-comment">//相册层</span><br><br>$.<span class="hljs-title function_">getJSON</span>(<span class="hljs-string">&#x27;test/photos.json?v=&#x27;</span>+<span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">json</span>)&#123;<br>  layer.<span class="hljs-title function_">photos</span>(&#123;<br>    <span class="hljs-attr">photos</span>: json <span class="hljs-comment">//格式见API文档手册页</span><br>    ,<span class="hljs-attr">anim</span>: <span class="hljs-number">5</span> <span class="hljs-comment">//0-6的选择，指定弹出图片动画类型，默认随机</span><br>  &#125;);<br>&#125;);<br><span class="hljs-comment">//显示自动关闭倒计秒数</span><br><br>layer.<span class="hljs-title function_">alert</span>(<span class="hljs-string">&#x27;在标题栏显示自动关闭倒计秒数&#x27;</span>, &#123;<br>  <span class="hljs-attr">time</span>: <span class="hljs-number">5</span>*<span class="hljs-number">1000</span><br>  ,<span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">layero, index</span>)&#123;<br>    <span class="hljs-keyword">var</span> timeNum = <span class="hljs-variable language_">this</span>.<span class="hljs-property">time</span>/<span class="hljs-number">1000</span>, setText = <span class="hljs-keyword">function</span>(<span class="hljs-params">start</span>)&#123;<br>      layer.<span class="hljs-title function_">title</span>((start ? timeNum : --timeNum) + <span class="hljs-string">&#x27; 秒后关闭&#x27;</span>, index);<br>    &#125;;<br>    <span class="hljs-title function_">setText</span>(!<span class="hljs-number">0</span>);<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">timer</span> = <span class="hljs-built_in">setInterval</span>(setText, <span class="hljs-number">1000</span>);<br>    <span class="hljs-keyword">if</span>(timeNum &lt;= <span class="hljs-number">0</span>) <span class="hljs-built_in">clearInterval</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">timer</span>);<br>  &#125;<br>  ,<span class="hljs-attr">end</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>    <span class="hljs-built_in">clearInterval</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">timer</span>);<br>  &#125;<br>&#125;);<br></code></pre></td></tr></table></figure><h1 id="Layui-表格"><a href="#Layui-表格" class="headerlink" title="Layui 表格"></a>Layui 表格</h1><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;utf-8&quot;</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>table模块快速使用<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/layui/css/layui.css&quot;</span> <span class="hljs-attr">media</span>=<span class="hljs-string">&quot;all&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><br> <br><span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;demo&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;test&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span><br> <br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/layui/layui.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"></span><br><span class="language-javascript">layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;table&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> table = layui.<span class="hljs-property">table</span>;</span><br><span class="language-javascript">  </span><br><span class="language-javascript">  <span class="hljs-comment">//第一个实例</span></span><br><span class="language-javascript">  table.<span class="hljs-title function_">render</span>(&#123;</span><br><span class="language-javascript">    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#demo&#x27;</span></span><br><span class="language-javascript">    ,<span class="hljs-attr">height</span>: <span class="hljs-number">312</span></span><br><span class="language-javascript">    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;../../demo/table/user/-page=1&amp;limit=30.js&#x27;</span> <span class="hljs-comment">//数据接口</span></span><br><span class="language-javascript">    ,<span class="hljs-attr">page</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">//开启分页</span></span><br><span class="language-javascript">    ,<span class="hljs-attr">cols</span>: [[ <span class="hljs-comment">//表头</span></span><br><span class="language-javascript">      &#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;id&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;ID&#x27;</span>, <span class="hljs-attr">width</span>:<span class="hljs-number">80</span>, <span class="hljs-attr">sort</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">fixed</span>: <span class="hljs-string">&#x27;left&#x27;</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;username&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;用户名&#x27;</span>, <span class="hljs-attr">width</span>:<span class="hljs-number">80</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sex&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;性别&#x27;</span>, <span class="hljs-attr">width</span>:<span class="hljs-number">80</span>, <span class="hljs-attr">sort</span>: <span class="hljs-literal">true</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;city&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;城市&#x27;</span>, <span class="hljs-attr">width</span>:<span class="hljs-number">80</span>&#125; </span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;sign&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;签名&#x27;</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">177</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;experience&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;积分&#x27;</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">80</span>, <span class="hljs-attr">sort</span>: <span class="hljs-literal">true</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;score&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;评分&#x27;</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">80</span>, <span class="hljs-attr">sort</span>: <span class="hljs-literal">true</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;classify&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;职业&#x27;</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">80</span>&#125;</span><br><span class="language-javascript">      ,&#123;<span class="hljs-attr">field</span>: <span class="hljs-string">&#x27;wealth&#x27;</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">&#x27;财富&#x27;</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">135</span>, <span class="hljs-attr">sort</span>: <span class="hljs-literal">true</span>&#125;</span><br><span class="language-javascript">    ]]</span><br><span class="language-javascript">  &#125;);</span><br><span class="language-javascript">  </span><br><span class="language-javascript">&#125;);</span><br><span class="language-javascript"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><br></code></pre></td></tr></table></figure><p>下面是目前 table 模块所支持的全部参数一览表，我们对重点参数进行了的详细说明，你可以点击下述表格最右侧的“示例”去查看</p><table><thead><tr><th align="left">参数</th><th align="left">类型</th><th align="left">说明</th><th align="left">示例值</th></tr></thead><tbody><tr><td align="left">elem</td><td align="left">String&#x2F;DOM</td><td align="left">指定原始 table 容器的选择器或 DOM，方法渲染方式必填</td><td align="left">“#demo”</td></tr><tr><td align="left">cols</td><td align="left">Array</td><td align="left">设置表头。值是一个二维数组。方法渲染方式必填</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#cols">详见表头参数</a></td></tr><tr><td align="left">url（等）</td><td align="left">-</td><td align="left">异步数据接口相关参数。其中 url 参数为必填项</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#async">详见异步参数</a></td></tr><tr><td align="left">toolbar</td><td align="left">String&#x2F;DOM&#x2F;Boolean</td><td align="left">开启表格头部工具栏区域，该参数支持四种类型值：toolbar: ‘#toolbarDemo’ <em>&#x2F;&#x2F;指向自定义工具栏模板选择器</em>toolbar: ‘<div>xxx</div>‘ <em>&#x2F;&#x2F;直接传入工具栏模板字符</em>toolbar: true <em>&#x2F;&#x2F;仅开启工具栏，不显示左侧模板</em>toolbar: ‘default’ <em>&#x2F;&#x2F;让工具栏左侧显示默认的内置模板</em>注意： 1. 该参数为 layui 2.4.0 开始新增。 2. 若需要“列显示隐藏”、“导出”、“打印”等功能，则必须开启该参数</td><td align="left">false</td></tr><tr><td align="left">defaultToolbar</td><td align="left">Array</td><td align="left">该参数可自由配置头部工具栏右侧的图标按钮</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#defaultToolbar">详见头工具栏图标</a></td></tr><tr><td align="left">width</td><td align="left">Number</td><td align="left">设定容器宽度。table容器的默认宽度是跟随它的父元素铺满，你也可以设定一个固定值，当容器中的内容超出了该宽度时，会自动出现横向滚动条。</td><td align="left">1000</td></tr><tr><td align="left">height</td><td align="left">Number&#x2F;String</td><td align="left">设定容器高度</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#height">详见height</a></td></tr><tr><td align="left">cellMinWidth</td><td align="left">Number</td><td align="left">（layui 2.2.1 新增）全局定义所有常规单元格的最小宽度（默认：60），一般用于列宽自动分配的情况。其优先级低于表头参数中的 minWidth</td><td align="left">100</td></tr><tr><td align="left">done</td><td align="left">Function</td><td align="left">数据渲染完的回调。你可以借此做一些其它的操作</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#done">详见 done 回调</a></td></tr><tr><td align="left">error</td><td align="left">Function</td><td align="left">数据请求失败的回调，返回两个参数：错误对象、内容 layui 2.6.0 新增</td><td align="left">-</td></tr><tr><td align="left">data</td><td align="left">Array</td><td align="left">直接赋值数据。既适用于只展示一页数据，也非常适用于对一段已知数据进行多页展示。</td><td align="left">[{}, {}, {}, {}, …]</td></tr><tr><td align="left">escape</td><td align="left">Boolean</td><td align="left">是否开启 xss 字符过滤（默认 false）layui 2.6.8 新增</td><td align="left">true</td></tr><tr><td align="left">totalRow</td><td align="left">Boolean&#x2F;String</td><td align="left">是否开启合计行区域</td><td align="left">false</td></tr><tr><td align="left">page</td><td align="left">Boolean&#x2F;Object</td><td align="left">开启分页（默认：false）。支持传入一个对象，里面可包含 <a href="https://layuiweb.com/doc/modules/laypage.html#options">laypage</a> 组件所有支持的参数（jump、elem除外）</td><td align="left">{theme: ‘#c00’}</td></tr><tr><td align="left">limit</td><td align="left">Number</td><td align="left">每页显示的条数（默认 10）。值需对应 limits 参数的选项。 注意：<em>优先级低于 page 参数中的 limit 参数</em></td><td align="left">30</td></tr><tr><td align="left">limits</td><td align="left">Array</td><td align="left">每页条数的选择项，默认：[10,20,30,40,50,60,70,80,90]。 注意：<em>优先级低于 page 参数中的 limits 参数</em></td><td align="left">[30,60,90]</td></tr><tr><td align="left">loading</td><td align="left">Boolean</td><td align="left">是否显示加载条（默认 true）。若为 false，则在切换分页时，不会出现加载条。该参数只适用于 url 参数开启的方式</td><td align="left">false</td></tr><tr><td align="left">title</td><td align="left">String</td><td align="left">定义 table 的大标题（在文件导出等地方会用到）</td><td align="left">“用户表”</td></tr><tr><td align="left">text</td><td align="left">Object</td><td align="left">自定义文本，如空数据时的异常提示等。</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#text">详见自定义文本</a></td></tr><tr><td align="left">autoSort</td><td align="left">Boolean</td><td align="left">默认 true，即直接由 table 组件在前端自动处理排序。 若为 false，则需自主排序，即由服务端返回排序好的数据</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#onsort">详见事件排序</a></td></tr><tr><td align="left">initSort</td><td align="left">Object</td><td align="left">初始排序状态。 用于在数据表格渲染完毕时，默认按某个字段排序。</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#initSort">详见初始排序</a></td></tr><tr><td align="left">id</td><td align="left">String</td><td align="left">设定容器唯一 id。id 是对表格的数据操作方法上是必要的传递条件，它是表格容器的索引，你在下文诸多地方都将会见识它的存在。  另外，若该参数未设置，则默认从 <em><table id="test"></table></em> 中的 id 属性值中获取。</td><td align="left">test</td></tr><tr><td align="left">skin（等）</td><td align="left">-</td><td align="left">设定表格各种外观、尺寸等</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#skin">详见表格风格</a></td></tr></tbody></table><p>cols - 表头参数一览表</p><p>相信我，在你还尚无法驾驭 layui table 的时候，你的所有焦点都应放在这里，它带引领你完成许多可见和不可见甚至你无法想象的工作。如果你采用的是方法渲染，cols 是一个二维数组，表头参数设定在数组内；如果你采用的自动渲染，表头参数的设定应放在 <em><th></em> 标签上</p><table><thead><tr><th align="left">参数</th><th align="left">类型</th><th align="left">说明</th><th align="left">示例值</th></tr></thead><tbody><tr><td align="left">field</td><td align="left">String</td><td align="left">设定字段名。非常重要，且是表格数据列的唯一标识</td><td align="left">username</td></tr><tr><td align="left">title</td><td align="left">String</td><td align="left">设定标题名称</td><td align="left">用户名</td></tr><tr><td align="left">width</td><td align="left">Number&#x2F;String</td><td align="left">设定列宽，若不填写，则自动分配；若填写，则支持值为：数字、百分比。 请结合实际情况，对不同列做不同设定。</td><td align="left">200 30%</td></tr><tr><td align="left">minWidth</td><td align="left">Number</td><td align="left">局部定义当前常规单元格的最小宽度（默认：60），一般用于列宽自动分配的情况。其优先级高于基础参数中的 cellMinWidth</td><td align="left">100</td></tr><tr><td align="left">type</td><td align="left">String</td><td align="left">设定列类型。可选值有：normal（常规列，无需设定）checkbox（复选框列）radio（单选框列，layui 2.4.0 新增）numbers（序号列）space（空列）</td><td align="left">任意一个可选值</td></tr><tr><td align="left">LAY_CHECKED</td><td align="left">Boolean</td><td align="left">是否全选状态（默认：false）。必须复选框列开启后才有效，如果设置 true，则表示复选框默认全部选中。</td><td align="left">true</td></tr><tr><td align="left">fixed</td><td align="left">String</td><td align="left">固定列。可选值有：<em>left</em>（固定在左）、<em>right</em>（固定在右）。一旦设定，对应的列将会被固定在左或右，不随滚动条而滚动。 注意：<em>如果是固定在左，该列必须放在表头最前面；如果是固定在右，该列必须放在表头最后面。</em></td><td align="left">left（同 true） right</td></tr><tr><td align="left">hide</td><td align="left">Boolean</td><td align="left">是否初始隐藏列，默认：false。layui 2.4.0 新增</td><td align="left">true</td></tr><tr><td align="left"></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left">totalRow</td><td align="left">Boolean&#x2F;String</td><td align="left">是否开启该列的自动合计功能，默认：false。当开启时，则默认由前端自动合计当前行数据。从 layui 2.5.6 开始： 若接口直接返回了合计行数据，则优先读取接口合计行数据，格式如下：<code>&lt;/&gt;code&#123;  &quot;code&quot;: 0,  &quot;totalRow&quot;: &#123;    &quot;score&quot;: &quot;666&quot;    ,&quot;experience&quot;: &quot;999&quot;  &#125;,  &quot;data&quot;: [&#123;&#125;, &#123;&#125;],  &quot;msg&quot;: &quot;&quot;,  &quot;count&quot;: 1000&#125;              </code>如上，在 totalRow 中返回所需统计的列字段名和值即可。 另外，totalRow 字段同样可以通过 parseData 回调来解析成为 table 组件所规定的数据格式。从 layui 2.6.3 开始，如果 totalRow 为一个 string 类型，则可解析为合计行的动态模板，如：<code>&lt;/&gt;codetotalRow: &#39;&#123;&#123; d.TOTAL_NUMS &#125;&#125; 单位&#39;//还比如只取整：&#39;&#123;&#123; parseInt(d.TOTAL_NUMS) &#125;&#125;&#39;              </code></td><td align="left">true</td></tr><tr><td align="left">totalRowText</td><td align="left">String</td><td align="left">用于显示自定义的合计文本。layui 2.4.0 新增</td><td align="left">“合计：”</td></tr><tr><td align="left"></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left">sort</td><td align="left">Boolean</td><td align="left">是否允许排序（默认：false）。如果设置 true，则在对应的表头显示排序icon，从而对列开启排序功能。注意：<em>不推荐对值同时存在“数字和普通字符”的列开启排序，因为会进入字典序比对</em>。比如：*’贤心’ &gt; ‘2’ &gt; ‘100’*，这可能并不是你想要的结果，但字典序排列算法（ASCII码比对）就是如此。</td><td align="left">true</td></tr><tr><td align="left">unresize</td><td align="left">Boolean</td><td align="left">是否禁用拖拽列宽（默认：false）。默认情况下会根据列类型（type）来决定是否禁用，如复选框列，会自动禁用。而其它普通列，默认允许拖拽列宽，当然你也可以设置 true 来禁用该功能。</td><td align="left">false</td></tr><tr><td align="left">edit</td><td align="left">String</td><td align="left">单元格编辑类型（默认不开启）目前只支持：<em>text</em>（输入框）</td><td align="left">text</td></tr><tr><td align="left">event</td><td align="left">String</td><td align="left">自定义单元格点击事件名，以便在 <a href="https://layuiweb.com/doc/modules/table.html#ontool">tool</a> 事件中完成对该单元格的业务处理</td><td align="left">任意字符</td></tr><tr><td align="left">style</td><td align="left">String</td><td align="left">自定义单元格样式。即传入 CSS 样式</td><td align="left">background-color: #5FB878; color: #fff;</td></tr><tr><td align="left">align</td><td align="left">String</td><td align="left">单元格排列方式。可选值有：<em>left</em>（默认）、<em>center</em>（居中）、<em>right</em>（居右）</td><td align="left">center</td></tr><tr><td align="left">colspan</td><td align="left">Number</td><td align="left">单元格所占列数（默认：1）。一般用于多级表头</td><td align="left">3</td></tr><tr><td align="left">rowspan</td><td align="left">Number</td><td align="left">单元格所占行数（默认：1）。一般用于多级表头</td><td align="left">2</td></tr><tr><td align="left">templet</td><td align="left">String</td><td align="left">自定义列模板，模板遵循 <a href="https://layuiweb.com/doc/modules/laytpl.html">laytpl</a> 语法。这是一个非常实用的功能，你可借助它实现逻辑处理，以及将原始数据转化成其它格式，如时间戳转化为日期字符等</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#templet">详见自定义模板</a></td></tr><tr><td align="left">toolbar</td><td align="left">String</td><td align="left">绑定工具条模板。可在每行对应的列中出现一些自定义的操作性按钮</td><td align="left"><a href="https://layuiweb.com/doc/modules/table.html#onrowtool">详见行工具事件</a></td></tr></tbody></table><h1 id="Layui-表单"><a href="#Layui-表单" class="headerlink" title="Layui 表单"></a>Layui 表单</h1><blockquote><p>在一个容器中设定 <em>class&#x3D;”layui-form”</em> 来标识一个表单元素块，通过规范好的HTML结构及CSS类，来组装成各式各样的表单元素，并通过内置的 <em>form模块</em> 来完成各种交互。</p></blockquote><blockquote><p>依赖加载模块：<a href="https://layui.gitee.io/v2/docs/modules/form.html">form</a> （请注意：如果不加载form模块，select、checkbox、radio等将无法显示，并且无法使用form相关功能）</p></blockquote><p>UI的最终呈现得益于 Form模块 的全自动渲染，她将原本普通的诸如select、checkbox、radio等元素重置为你所看到的模样。</p><h2 id="渲染"><a href="#渲染" class="headerlink" title="渲染"></a>渲染</h2><p>尽管 form 会对表单进行自动渲染，但当元素动态插入时，需通过核心方法 <em>form.render(type, filter)</em> 来进行渲染。<br>其中参数 <code>type</code>为表单的元素类型，可选。默认对全部类型的表单进行一次渲染。也可指向 type 进行渲染：</p><table><thead><tr><th align="left">type</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">select</td><td align="left">渲染 select 选择框</td></tr><tr><td align="left">checkbox</td><td align="left">渲染 checkbox 复选框（含开关）</td></tr><tr><td align="left">radio</td><td align="left">渲染 radio 单选框框</td></tr></tbody></table><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 示例</span><br><span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>;<br> <br><span class="hljs-comment">// 一般当表单存在动态生成时，进行渲染</span><br>form.<span class="hljs-title function_">render</span>(); <span class="hljs-comment">// 渲染全部</span><br>form.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;select&#x27;</span>); <span class="hljs-comment">//渲染 select 选择框</span><br></code></pre></td></tr></table></figure><p>第二个参数 <code>filter</code> 为 <em>class&#x3D;”layui-form”</em> 所在元素的 <em>lay-filter&#x3D;””</em> 的值。你可以借助该参数，对表单完成区域渲染。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;test1&quot;</span>&gt;</span><br>  …<br><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>      <br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"></span><br><span class="language-javascript">layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;form&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>;</span><br><span class="language-javascript"> </span><br><span class="language-javascript">  <span class="hljs-comment">// 一般当表单存在动态生成时，进行渲染</span></span><br><span class="language-javascript">  form.<span class="hljs-title function_">render</span>(<span class="hljs-literal">null</span>, <span class="hljs-string">&#x27;test1&#x27;</span>); <span class="hljs-comment">// 渲染所在容器内的全部表单</span></span><br><span class="language-javascript">  form.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;select&#x27;</span>, <span class="hljs-string">&#x27;test1&#x27;</span>); <span class="hljs-comment">// 渲染所在容器内的 select 元素</span></span><br><span class="language-javascript">&#125;);</span><br><span class="language-javascript"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br></code></pre></td></tr></table></figure><h3 id="定向渲染-注：v2-7-0-新增"><a href="#定向渲染-注：v2-7-0-新增" class="headerlink" title="定向渲染 - 注：v2.7.0 新增"></a><strong>定向渲染</strong> - 注：v2.7.0 新增</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form&quot;</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;select-id&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;a&quot;</span>&gt;</span>A<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br> <br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"> </span><br><span class="language-javascript">layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;form&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> $ = layui.<span class="hljs-property">$</span>;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>;</span><br><span class="language-javascript">  </span><br><span class="language-javascript">  <span class="hljs-comment">// 定向渲染（一般当表单存在动态生成时，进行渲染）</span></span><br><span class="language-javascript">  form.<span class="hljs-title function_">render</span>($(<span class="hljs-string">&#x27;#select-id&#x27;</span>)); <span class="hljs-comment">// 传入需要渲染的相应表单元素的 jQuery 对象 </span></span><br><span class="language-javascript">&#125;);</span><br><span class="language-javascript"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br></code></pre></td></tr></table></figure><h2 id="属性"><a href="#属性" class="headerlink" title="属性"></a>属性</h2><p>事实上在使用表单时，你的一半精力可能会在元素本身上。所以我们把一些基础属性的配置恰恰安放在了标签本身上。如：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;email&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;checkbox&quot;</span> <span class="hljs-attr">checked</span> <span class="hljs-attr">lay-skin</span>=<span class="hljs-string">&quot;switch&quot;</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;encrypt&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;是否加密&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">lay-submit</span>&gt;</span>提交<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br></code></pre></td></tr></table></figure><p>上述 <code>lay-</code> 前缀的属性即是表单所能识别的元素属性，他们可以使得一些交互操作交由 form 模块内部处理，或者借助 form 提供的 api 精确操作。目前我们可支持的属性如下表所示：</p><table><thead><tr><th align="left">属性名</th><th align="left">属性值</th><th align="left">说明</th></tr></thead><tbody><tr><td align="left">title</td><td align="left">任意字符</td><td align="left">设定元素名称，一般用于 checkbox、radio 框</td></tr><tr><td align="left">lay-filter</td><td align="left">任意字符</td><td align="left">过滤器，主要用于事件匹配</td></tr><tr><td align="left">lay-search</td><td align="left">default （等同空字符） cs （区分字母大小写）</td><td align="left">用于给 select 开启搜索功能。默认不区分字母大小写（注：v2.7.0 新增）</td></tr><tr><td align="left">lay-skin</td><td align="left">switch（开关风格） primary（原始风格）</td><td align="left">定义元素的风格，目前只对 <em>checkbox</em> 元素有效，可将其转变为开关样式</td></tr><tr><td align="left">lay-ignore</td><td align="left">任意字符或不设值</td><td align="left">是否忽略元素美化处理。设置后，将不会对该元素进行初始化渲染，即保留系统风格</td></tr><tr><td align="left">lay-verify</td><td align="left">required（必填项） phone（手机号） email（邮箱） url（网址） number（数字） date（日期） identity（身份证） 自定义值</td><td align="left">同时支持多条规则的验证，格式：&#96;lay-verify&#x3D;”验证A</td></tr><tr><td align="left">lay-verType</td><td align="left">tips（吸附层） alert（对话框） msg（默认）</td><td align="left">用于定义异常提示层模式。</td></tr><tr><td align="left">lay-reqText</td><td align="left">任意字符</td><td align="left">用于自定义必填项（即设定了 lay-verify&#x3D;”required” 的表单）的提示文本</td></tr><tr><td align="left">lay-submit</td><td align="left">无需填写值</td><td align="left">绑定触发提交的元素，如button</td></tr></tbody></table><h2 id="API"><a href="#API" class="headerlink" title="API"></a>API</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>; <span class="hljs-comment">// 获得 form 模块对象</span><br> <br>form.<span class="hljs-title function_">render</span>(type, filter); <span class="hljs-comment">// 渲染 - 核心方法</span><br>form.<span class="hljs-title function_">validate</span>(elem); <span class="hljs-comment">// 执行验证，elem 为需要验证的区域选择器或 DOM 对象  注：v2.7.0 新增</span><br>form.<span class="hljs-title function_">verify</span>(obj); <span class="hljs-comment">// 定义表单验证的规则（详见下文）</span><br>form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;event(filter)&#x27;</span>, callback); <span class="hljs-comment">// 事件</span><br>form.<span class="hljs-title function_">val</span>(filter, object); <span class="hljs-comment">// 表单赋值或取值。 如果 object 参数存在，则为赋值，否则为取值。</span><br>form.<span class="hljs-title function_">submit</span>(filter, callback); <span class="hljs-comment">// 用于执行指定表单的提交 注：v2.7.0 新增</span><br>form.<span class="hljs-property">config</span>; <span class="hljs-comment">// 获取 form 模块的配置信息</span><br>form.<span class="hljs-title function_">set</span>(options); <span class="hljs-comment">// 设置 form 的配置信息</span><br></code></pre></td></tr></table></figure><h2 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h2><p>语法：<code>form.on(&#39;event(filter)&#39;, callback);</code></p><table><thead><tr><th align="left">event</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">select</td><td align="left">触发select下拉选择事件</td></tr><tr><td align="left">checkbox</td><td align="left">触发checkbox复选框勾选事件</td></tr><tr><td align="left">switch</td><td align="left">触发checkbox复选框开关事件</td></tr><tr><td align="left">radio</td><td align="left">触发radio单选框事件</td></tr><tr><td align="left">submit</td><td align="left">触发表单提交事件</td></tr></tbody></table><p>默认情况下，事件所触发的是全部的 form 模块元素，但如果你只想触发某一个元素，使用事件过滤器即可。<br>如：<code>&lt;select lay-filter=&quot;test&quot;&gt;&lt;/select&gt;</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(test)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data);<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="select-事件"><a href="#select-事件" class="headerlink" title="select 事件"></a>select 事件</h3><p>下拉选择框被选中时触发，回调函数返回一个object参数，携带两个成员：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;select(filter)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>); <span class="hljs-comment">//得到select原始DOM对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">value</span>); <span class="hljs-comment">//得到被选中的值</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">othis</span>); <span class="hljs-comment">//得到美化后的DOM对象</span><br>&#125;);<br></code></pre></td></tr></table></figure><p>请注意：如果你想触发所有的select，去掉过滤器*(filter)*即可。下面将不再对此进行备注。</p><h3 id="checkbox-事件"><a href="#checkbox-事件" class="headerlink" title="checkbox 事件"></a>checkbox 事件</h3><p>复选框点击勾选时触发，回调函数返回一个object参数，携带两个成员：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;checkbox(filter)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>); <span class="hljs-comment">//得到checkbox原始DOM对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>.<span class="hljs-property">checked</span>); <span class="hljs-comment">//是否被选中，true或者false</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">value</span>); <span class="hljs-comment">//复选框value值，也可以通过data.elem.value得到</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">othis</span>); <span class="hljs-comment">//得到美化后的DOM对象</span><br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="switch-事件"><a href="#switch-事件" class="headerlink" title="switch 事件"></a>switch 事件</h3><p>开关被点击时触发，回调函数返回一个object参数，携带两个成员：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;switch(filter)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>); <span class="hljs-comment">//得到checkbox原始DOM对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>.<span class="hljs-property">checked</span>); <span class="hljs-comment">//开关是否开启，true或者false</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">value</span>); <span class="hljs-comment">//开关value值，也可以通过data.elem.value得到</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">othis</span>); <span class="hljs-comment">//得到美化后的DOM对象</span><br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="radio-事件"><a href="#radio-事件" class="headerlink" title="radio 事件"></a>radio 事件</h3><p>radio单选框被点击时触发，回调函数返回一个object参数，携带两个成员：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;radio(filter)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>); <span class="hljs-comment">//得到radio原始DOM对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">value</span>); <span class="hljs-comment">//被点击的radio的value值</span><br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="submit-事件"><a href="#submit-事件" class="headerlink" title="submit 事件"></a>submit 事件</h3><p>按钮点击或者表单被执行提交时触发，其中回调函数只有在验证全部通过后才会进入，回调返回三个成员：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;submit(*)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">elem</span>) <span class="hljs-comment">//被执行事件的元素DOM对象，一般为button对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">form</span>) <span class="hljs-comment">//被执行提交的form对象，一般在存在form标签时才会返回</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data.<span class="hljs-property">field</span>) <span class="hljs-comment">//当前容器的全部表单字段，名值对形式：&#123;name: value&#125;</span><br>  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; <span class="hljs-comment">//阻止表单跳转。如果需要表单跳转，去掉这段即可。</span><br>&#125;);<br></code></pre></td></tr></table></figure><p>再次温馨提示：上述的*submit(*)*中的 *** 号为事件过滤器的值，是在你绑定执行提交的元素时设定的，如：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">lay-submit</span> <span class="hljs-attr">lay-filter</span>=<span class="hljs-string">&quot;*&quot;</span>&gt;</span>提交<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br></code></pre></td></tr></table></figure><p>你可以把<em>号换成任意的值，如：</em>lay-filter&#x3D;”go”*，但触发事件时也要改成 <em>form.on(‘submit(go)’, callback);</em></p><h3 id="执行提交方法："><a href="#执行提交方法：" class="headerlink" title="执行提交方法："></a><strong>执行提交方法：</strong></h3><p>有时我们未必要通过点击表单内的按钮来进行提交，这时需要用到提交方法：<code>form.submit(filter, callback);</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">&quot;layui-form&quot;</span> lay-filter=<span class="hljs-string">&quot;test1&quot;</span>&gt;<br>  &lt;!-- 表单内部 --&gt;<br>&lt;/div&gt;<br> <br><span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;testSubmitBtn&quot;</span>&gt;</span>任意位置按钮<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span><br> <br><span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="language-javascript"><span class="language-xml">layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;form&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123; </span></span><br><span class="language-javascript"><span class="language-xml">  <span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>;</span></span><br><span class="language-javascript"><span class="language-xml">  </span></span><br><span class="language-javascript"><span class="language-xml">  <span class="hljs-comment">//方法提交</span></span></span><br><span class="language-javascript"><span class="language-xml">  $(<span class="hljs-string">&#x27;#testSubmitBtn&#x27;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;click&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;</span></span><br><span class="language-javascript"><span class="language-xml">    form.<span class="hljs-title function_">submit</span>(<span class="hljs-string">&#x27;test1&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123; <span class="hljs-comment">// 注：v2.7.0 新增</span></span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-comment">// 回调函数返回结果跟上述 submit 事件完全一致</span></span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-keyword">var</span> field = data.<span class="hljs-property">field</span>;</span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-comment">// do something</span></span></span><br><span class="language-javascript"><span class="language-xml">    &#125;);</span></span><br><span class="language-javascript"><span class="language-xml">    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;</span></span><br><span class="language-javascript"><span class="language-xml">  &#125;);</span></span><br><span class="language-javascript"><span class="language-xml">&#125;);</span></span><br><span class="language-javascript"><span class="language-xml"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span><br></code></pre></td></tr></table></figure><h2 id="表单赋值-取值"><a href="#表单赋值-取值" class="headerlink" title="表单赋值 &#x2F; 取值"></a>表单赋值 &#x2F; 取值</h2><p>语法：<em>form.val(‘filter’, object);</em></p><p>用于给指定表单集合的元素赋值和取值。如果 object 参数存在，则为赋值；如果 object 参数不存在，则为取值。<br>注：其中「取值」功能为 layui 2.5.5 开始新增</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">//给表单赋值</span><br>form.<span class="hljs-title function_">val</span>(<span class="hljs-string">&quot;formTest&quot;</span>, &#123; <span class="hljs-comment">//formTest 即 class=&quot;layui-form&quot; 所在元素属性 lay-filter=&quot;&quot; 对应的值</span><br>  <span class="hljs-string">&quot;username&quot;</span>: <span class="hljs-string">&quot;贤心&quot;</span> <span class="hljs-comment">// &quot;name&quot;: &quot;value&quot;</span><br>  ,<span class="hljs-string">&quot;sex&quot;</span>: <span class="hljs-string">&quot;女&quot;</span><br>  ,<span class="hljs-string">&quot;auth&quot;</span>: <span class="hljs-number">3</span><br>  ,<span class="hljs-string">&quot;check[write]&quot;</span>: <span class="hljs-literal">true</span><br>  ,<span class="hljs-string">&quot;open&quot;</span>: <span class="hljs-literal">false</span><br>  ,<span class="hljs-string">&quot;desc&quot;</span>: <span class="hljs-string">&quot;我爱layui&quot;</span><br>&#125;);<br> <br><span class="hljs-comment">//获取表单区域所有值</span><br><span class="hljs-keyword">var</span> data1 = form.<span class="hljs-title function_">val</span>(<span class="hljs-string">&quot;formTest&quot;</span>);<br></code></pre></td></tr></table></figure><p>第二个参数中的键值是表单元素对应的 <em>name</em> 和 <em>value</em>。</p><h2 id="表单验证"><a href="#表单验证" class="headerlink" title="表单验证"></a>表单验证</h2><p>我们对表单的验证进行了非常巧妙的支持，大多数时候你只需要在表单元素上加上 <em>lay-verify&#x3D;””</em> 属性值即可。如：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;email&quot;</span>&gt;</span> <br> <br>还同时支持多条规则的验证，如下：<br><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;required|phone|number&quot;</span>&gt;</span><br></code></pre></td></tr></table></figure><p>上述对输入框定义了一个邮箱规则的校验，它会在 form 模块内部完成。目前我们内置的校验支持见上文的：<a href="https://layui.gitee.io/v2/docs/modules/form.html#attr">预设元素属性</a></p><h3 id="定义验证规则"><a href="#定义验证规则" class="headerlink" title="定义验证规则"></a><strong>定义验证规则</strong></h3><p>除了内置的校验规则外，你还可以自定义验证规则，通常对于比较复杂的校验，这是非常有必要的。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs javascript">form.<span class="hljs-title function_">verify</span>(&#123;<br>  <span class="hljs-attr">username</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">value, item</span>)&#123; <span class="hljs-comment">//value：表单的值、item：表单的DOM对象</span><br>    <span class="hljs-keyword">if</span>(!<span class="hljs-keyword">new</span> <span class="hljs-title class_">RegExp</span>(<span class="hljs-string">&quot;^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$&quot;</span>).<span class="hljs-title function_">test</span>(value))&#123;<br>      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;用户名不能有特殊字符&#x27;</span>;<br>    &#125;<br>    <span class="hljs-keyword">if</span>(<span class="hljs-regexp">/(^\_)|(\__)|(\_+$)/</span>.<span class="hljs-title function_">test</span>(value))&#123;<br>      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;用户名首尾不能出现下划线\&#x27;_\&#x27;&#x27;</span>;<br>    &#125;<br>    <span class="hljs-keyword">if</span>(<span class="hljs-regexp">/^\d+\d+\d$/</span>.<span class="hljs-title function_">test</span>(value))&#123;<br>      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;用户名不能全为数字&#x27;</span>;<br>    &#125;<br>    <br>    <span class="hljs-comment">//如果不想自动弹出默认提示框，可以直接返回 true，这时你可以通过其他任意方式提示（v2.5.7 新增）</span><br>    <span class="hljs-keyword">if</span>(value === <span class="hljs-string">&#x27;xxx&#x27;</span>)&#123;<br>      <span class="hljs-title function_">alert</span>(<span class="hljs-string">&#x27;用户名不能为敏感词&#x27;</span>);<br>      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>    &#125;<br>  &#125;<br>  <br>  <span class="hljs-comment">//我们既支持上述函数式的方式，也支持下述数组的形式</span><br>  <span class="hljs-comment">//数组的两个值分别代表：[正则匹配、匹配不符时的提示文字]</span><br>  ,<span class="hljs-attr">pass</span>: [<br>    <span class="hljs-regexp">/^[\S]&#123;6,12&#125;$/</span><br>    ,<span class="hljs-string">&#x27;密码必须6到12位，且不能出现空格&#x27;</span><br>  ] <br>&#125;);<br></code></pre></td></tr></table></figure><p>当你自定义了类似上面的验证规则后，你只需要把 key 赋值给输入框的 <em>lay-verify</em> 属性即可：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;/&gt;</span>code<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;username&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;username&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;password&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;pass&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;pass&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;ch&lt;input type=&quot;</span><span class="hljs-attr">text</span>&quot; <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;username&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;username&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;password&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;pass&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;pass&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;checkbox&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;agreement&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;required&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;同意&quot;</span>&gt;</span>eckbox&quot; name=&quot;agreement&quot; lay-verify=&quot;required&quot; title=&quot;同意&quot;&gt;<br></code></pre></td></tr></table></figure><p>当表单提交时，<strong>自动触发验证</strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> layer = layui.<span class="hljs-property">layer</span>;<br><span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>;<br> <br><span class="hljs-comment">// 提交事件</span><br>form.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;submit(*)&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)&#123;<br>  <span class="hljs-keyword">var</span> field = data.<span class="hljs-property">field</span>;<br>  <br>  <span class="hljs-comment">// 若需验证 checkbox 是否勾选，则需判断其值是否存在，如：</span><br>  <span class="hljs-keyword">if</span>(!field.<span class="hljs-property">agreement</span>)&#123;<br>    layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;请同意&#x27;</span>);<br>    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>  &#125;<br>  <br>  <span class="hljs-comment">// 验证均通过后的操作（如 Ajax 提交）</span><br>  <span class="hljs-comment">// …</span><br>  <br>  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="主动触发验证"><a href="#主动触发验证" class="headerlink" title="主动触发验证"></a><strong>主动触发验证</strong></h3><p>方法：<code>form.validate(elem);</code> 若验证通过返回 true，否则 false</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form&quot;</span>&gt;</span>  <br>  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-item&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-label&quot;</span>&gt;</span>手机<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-block&quot;</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;tel&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;phone&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;required|phone&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input demo-phone&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-item&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-form-label&quot;</span>&gt;</span>验证码<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input-inline&quot;</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;vercode&quot;</span> <span class="hljs-attr">lay-verify</span>=<span class="hljs-string">&quot;required&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-input&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-inline&quot;</span>&gt;</span> <br>      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;button&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;layui-btn layui-btn-primary&quot;</span> <span class="hljs-attr">lay-on</span>=<span class="hljs-string">&quot;get-vercode&quot;</span>&gt;</span>获取验证码<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br> <br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"></span><br><span class="language-javascript">layui.<span class="hljs-title function_">use</span>([<span class="hljs-string">&#x27;form&#x27;</span>, <span class="hljs-string">&#x27;util&#x27;</span>], <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> form = layui.<span class="hljs-property">form</span>;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> layer = layui.<span class="hljs-property">layer</span>;</span><br><span class="language-javascript">  <span class="hljs-keyword">var</span> util = layui.<span class="hljs-property">util</span>;</span><br><span class="language-javascript">  </span><br><span class="language-javascript">  <span class="hljs-comment">// 自定义普通事件</span></span><br><span class="language-javascript">  util.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;lay-on&#x27;</span>, &#123;</span><br><span class="language-javascript">    <span class="hljs-string">&quot;get-vercode&quot;</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">othis</span>)&#123;</span><br><span class="language-javascript">      <span class="hljs-keyword">var</span> isValid = form.<span class="hljs-title function_">validate</span>(<span class="hljs-string">&#x27;.demo-phone&#x27;</span>);  <span class="hljs-comment">// 注：v2.7.0 新增</span></span><br><span class="language-javascript">  </span><br><span class="language-javascript">      <span class="hljs-comment">// 验证通过</span></span><br><span class="language-javascript">      <span class="hljs-keyword">if</span>(isValid)&#123;</span><br><span class="language-javascript">        layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;手机号验证通过，执行发送验证码的操作&#x27;</span>);</span><br><span class="language-javascript">      &#125;</span><br><span class="language-javascript">    &#125;</span><br><span class="language-javascript">  &#125;);</span><br><span class="language-javascript">&#125;);</span><br><span class="language-javascript"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br></code></pre></td></tr></table></figure><h1 id="Layui-日期与时间选择"><a href="#Layui-日期与时间选择" class="headerlink" title="Layui 日期与时间选择"></a>Layui 日期与时间选择</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;script&gt;<br>layui.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;laydate&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>  <span class="hljs-keyword">var</span> laydate = layui.<span class="hljs-property">laydate</span>;<br>  <br>  <span class="hljs-comment">//常规用法</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test1&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//国际版</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test1-1&#x27;</span><br>    ,<span class="hljs-attr">lang</span>: <span class="hljs-string">&#x27;en&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//年选择器</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test2&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;year&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//年月选择器</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test3&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;month&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//时间选择器</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test4&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;time&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//日期时间选择器</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test5&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;datetime&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//日期范围</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test6&#x27;</span><br>    <span class="hljs-comment">//设置开始日期、日期日期的 input 选择器</span><br>    <span class="hljs-comment">//数组格式为 2.6.6 开始新增，之前版本直接配置 true 或任意分割字符即可</span><br>    ,<span class="hljs-attr">range</span>: [<span class="hljs-string">&#x27;#test-startDate-1&#x27;</span>, <span class="hljs-string">&#x27;#test-endDate-1&#x27;</span>]<br>  &#125;);<br>  <br>  <span class="hljs-comment">//年范围</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test7&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;year&#x27;</span><br>    ,<span class="hljs-attr">range</span>: <span class="hljs-literal">true</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//年月范围</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test8&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;month&#x27;</span><br>    ,<span class="hljs-attr">range</span>: <span class="hljs-literal">true</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//时间范围</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test9&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;time&#x27;</span><br>    ,<span class="hljs-attr">range</span>: <span class="hljs-literal">true</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//日期时间范围</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test10&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;datetime&#x27;</span><br>    ,<span class="hljs-attr">range</span>: <span class="hljs-literal">true</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//自定义格式</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test11&#x27;</span><br>    ,<span class="hljs-attr">format</span>: <span class="hljs-string">&#x27;yyyy年MM月dd日&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test12&#x27;</span><br>    ,<span class="hljs-attr">format</span>: <span class="hljs-string">&#x27;dd/MM/yyyy&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test13&#x27;</span><br>    ,<span class="hljs-attr">format</span>: <span class="hljs-string">&#x27;yyyyMMdd&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test14&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;time&#x27;</span><br>    ,<span class="hljs-attr">format</span>: <span class="hljs-string">&#x27;H点m分&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test15&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;month&#x27;</span><br>    ,<span class="hljs-attr">range</span>: <span class="hljs-string">&#x27;~&#x27;</span><br>    ,<span class="hljs-attr">format</span>: <span class="hljs-string">&#x27;yyyy-MM&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test16&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;datetime&#x27;</span><br>    ,<span class="hljs-attr">range</span>: <span class="hljs-string">&#x27;到&#x27;</span><br>    ,<span class="hljs-attr">format</span>: <span class="hljs-string">&#x27;yyyy年M月d日H时m分s秒&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//开启公历节日</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test17&#x27;</span><br>    ,<span class="hljs-attr">calendar</span>: <span class="hljs-literal">true</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//自定义重要日</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test18&#x27;</span><br>    ,<span class="hljs-attr">mark</span>: &#123;<br>      <span class="hljs-string">&#x27;0-10-14&#x27;</span>: <span class="hljs-string">&#x27;生日&#x27;</span><br>      ,<span class="hljs-string">&#x27;0-12-31&#x27;</span>: <span class="hljs-string">&#x27;跨年&#x27;</span> <span class="hljs-comment">//每年的日期</span><br>      ,<span class="hljs-string">&#x27;0-0-10&#x27;</span>: <span class="hljs-string">&#x27;工资&#x27;</span> <span class="hljs-comment">//每月某天</span><br>      ,<span class="hljs-string">&#x27;0-0-15&#x27;</span>: <span class="hljs-string">&#x27;月中&#x27;</span><br>      ,<span class="hljs-string">&#x27;2017-8-15&#x27;</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//如果为空字符，则默认显示数字+徽章</span><br>      ,<span class="hljs-string">&#x27;2099-10-14&#x27;</span>: <span class="hljs-string">&#x27;呵呵&#x27;</span><br>    &#125;<br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">value, date</span>)&#123;<br>      <span class="hljs-keyword">if</span>(date.<span class="hljs-property">year</span> === <span class="hljs-number">2017</span> &amp;&amp; date.<span class="hljs-property">month</span> === <span class="hljs-number">8</span> &amp;&amp; date.<span class="hljs-property">date</span> === <span class="hljs-number">15</span>)&#123; <span class="hljs-comment">//点击2017年8月15日，弹出提示语</span><br>        layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;这一天是：中国人民抗日战争胜利72周年&#x27;</span>);<br>      &#125;<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//限定可选日期</span><br>  <span class="hljs-keyword">var</span> ins22 = laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-limit1&#x27;</span><br>    ,<span class="hljs-attr">min</span>: <span class="hljs-string">&#x27;2016-10-14&#x27;</span><br>    ,<span class="hljs-attr">max</span>: <span class="hljs-string">&#x27;2080-10-14&#x27;</span><br>    ,<span class="hljs-attr">ready</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>      ins22.<span class="hljs-title function_">hint</span>(<span class="hljs-string">&#x27;日期可选值设定在 &lt;br&gt; 2016-10-14 到 2080-10-14&#x27;</span>);<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//前后若干天可选，这里以7天为例</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-limit2&#x27;</span><br>    ,<span class="hljs-attr">min</span>: -<span class="hljs-number">7</span><br>    ,<span class="hljs-attr">max</span>: <span class="hljs-number">7</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//限定可选时间</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-limit3&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;time&#x27;</span><br>    ,<span class="hljs-attr">min</span>: <span class="hljs-string">&#x27;09:30:00&#x27;</span><br>    ,<span class="hljs-attr">max</span>: <span class="hljs-string">&#x27;17:30:00&#x27;</span><br>    ,<span class="hljs-attr">btns</span>: [<span class="hljs-string">&#x27;clear&#x27;</span>, <span class="hljs-string">&#x27;confirm&#x27;</span>]<br>  &#125;);<br>  <br>  <span class="hljs-comment">//同时绑定多个</span><br>  <span class="hljs-title function_">lay</span>(<span class="hljs-string">&#x27;.test-item&#x27;</span>).<span class="hljs-title function_">each</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>    laydate.<span class="hljs-title function_">render</span>(&#123;<br>      <span class="hljs-attr">elem</span>: <span class="hljs-variable language_">this</span><br>      ,<span class="hljs-attr">trigger</span>: <span class="hljs-string">&#x27;click&#x27;</span><br>    &#125;);<br>  &#125;);<br>  <br>  <span class="hljs-comment">//初始赋值</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test19&#x27;</span><br>    ,<span class="hljs-attr">value</span>: <span class="hljs-string">&#x27;2016-10-14&#x27;</span><br>    ,<span class="hljs-attr">isInitValue</span>: <span class="hljs-literal">true</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//选中后的回调</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test20&#x27;</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">value, date</span>)&#123;<br>      layer.<span class="hljs-title function_">alert</span>(<span class="hljs-string">&#x27;你选择的日期是：&#x27;</span> + value + <span class="hljs-string">&#x27;&lt;br&gt;获得的对象是&#x27;</span> + <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(date));<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//日期切换的回调</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test21&#x27;</span><br>    ,<span class="hljs-attr">change</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">value, date</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;你选择的日期是：&#x27;</span> + value + <span class="hljs-string">&#x27;&lt;br&gt;&lt;br&gt;获得的对象是&#x27;</span> + <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(date));<br>    &#125;<br>  &#125;);<br>  <span class="hljs-comment">//不出现底部栏</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test22&#x27;</span><br>    ,<span class="hljs-attr">showBottom</span>: <span class="hljs-literal">false</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//只出现确定按钮</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test23&#x27;</span><br>    ,<span class="hljs-attr">btns</span>: [<span class="hljs-string">&#x27;confirm&#x27;</span>]<br>  &#125;);<br>  <br>  <span class="hljs-comment">//自定义事件</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test24&#x27;</span><br>    ,<span class="hljs-attr">trigger</span>: <span class="hljs-string">&#x27;mousedown&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//点我触发</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test25&#x27;</span><br>    ,<span class="hljs-attr">eventElem</span>: <span class="hljs-string">&#x27;#test25-1&#x27;</span><br>    ,<span class="hljs-attr">trigger</span>: <span class="hljs-string">&#x27;click&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//双击我触发</span><br>  <span class="hljs-title function_">lay</span>(<span class="hljs-string">&#x27;#test26-1&#x27;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;dblclick&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>    laydate.<span class="hljs-title function_">render</span>(&#123;<br>      <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test26&#x27;</span><br>      ,<span class="hljs-attr">show</span>: <span class="hljs-literal">true</span><br>      ,<span class="hljs-attr">closeStop</span>: <span class="hljs-string">&#x27;#test26-1&#x27;</span><br>    &#125;);<br>  &#125;);<br>  <br>  <span class="hljs-comment">//日期只读</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test27&#x27;</span><br>    ,<span class="hljs-attr">trigger</span>: <span class="hljs-string">&#x27;click&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//非input元素</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test28&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//墨绿主题</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test29&#x27;</span><br>    ,<span class="hljs-attr">theme</span>: <span class="hljs-string">&#x27;molv&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//自定义颜色</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test30&#x27;</span><br>    ,<span class="hljs-attr">theme</span>: <span class="hljs-string">&#x27;#393D49&#x27;</span><br>  &#125;);<br>  <br>  <span class="hljs-comment">//格子主题</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test31&#x27;</span><br>    ,<span class="hljs-attr">theme</span>: <span class="hljs-string">&#x27;grid&#x27;</span><br>  &#125;);<br>  <br>  <br>  <span class="hljs-comment">//直接嵌套显示</span><br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-n1&#x27;</span><br>    ,<span class="hljs-attr">position</span>: <span class="hljs-string">&#x27;static&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-n2&#x27;</span><br>    ,<span class="hljs-attr">position</span>: <span class="hljs-string">&#x27;static&#x27;</span><br>    ,<span class="hljs-attr">lang</span>: <span class="hljs-string">&#x27;en&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-n3&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;month&#x27;</span><br>    ,<span class="hljs-attr">position</span>: <span class="hljs-string">&#x27;static&#x27;</span><br>  &#125;);<br>  laydate.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test-n4&#x27;</span><br>    ,<span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;time&#x27;</span><br>    ,<span class="hljs-attr">position</span>: <span class="hljs-string">&#x27;static&#x27;</span><br>  &#125;);<br>&#125;);<br>&lt;/script&gt;<br></code></pre></td></tr></table></figure><h1 id="Layui-上传文件"><a href="#Layui-上传文件" class="headerlink" title="Layui 上传文件"></a>Layui 上传文件</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;script&gt;<br>layui.<span class="hljs-title function_">use</span>([<span class="hljs-string">&#x27;upload&#x27;</span>, <span class="hljs-string">&#x27;element&#x27;</span>, <span class="hljs-string">&#x27;layer&#x27;</span>], <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>  <span class="hljs-keyword">var</span> $ = layui.<span class="hljs-property">jquery</span><br>  ,upload = layui.<span class="hljs-property">upload</span><br>  ,element = layui.<span class="hljs-property">element</span><br>  ,layer = layui.<span class="hljs-property">layer</span>;<br>  <br>  <span class="hljs-comment">//常规使用 - 普通图片上传</span><br>  <span class="hljs-keyword">var</span> uploadInst = upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test1&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;https://httpbin.org/post&#x27;</span> <span class="hljs-comment">//此处用的是第三方的 http 请求演示，实际使用时改成您自己的上传接口即可。</span><br>    ,<span class="hljs-attr">before</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>)&#123;<br>      <span class="hljs-comment">//预读本地文件示例，不支持ie8</span><br>      obj.<span class="hljs-title function_">preview</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">index, file, result</span>)&#123;<br>        $(<span class="hljs-string">&#x27;#demo1&#x27;</span>).<span class="hljs-title function_">attr</span>(<span class="hljs-string">&#x27;src&#x27;</span>, result); <span class="hljs-comment">//图片链接（base64）</span><br>      &#125;);<br>      <br>      element.<span class="hljs-title function_">progress</span>(<span class="hljs-string">&#x27;demo&#x27;</span>, <span class="hljs-string">&#x27;0%&#x27;</span>); <span class="hljs-comment">//进度条复位</span><br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传中&#x27;</span>, &#123;<span class="hljs-attr">icon</span>: <span class="hljs-number">16</span>, <span class="hljs-attr">time</span>: <span class="hljs-number">0</span>&#125;);<br>    &#125;<br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      <span class="hljs-comment">//如果上传失败</span><br>      <span class="hljs-keyword">if</span>(res.<span class="hljs-property">code</span> &gt; <span class="hljs-number">0</span>)&#123;<br>        <span class="hljs-keyword">return</span> layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传失败&#x27;</span>);<br>      &#125;<br>      <span class="hljs-comment">//上传成功的一些操作</span><br>      <span class="hljs-comment">//……</span><br>      $(<span class="hljs-string">&#x27;#demoText&#x27;</span>).<span class="hljs-title function_">html</span>(<span class="hljs-string">&#x27;&#x27;</span>); <span class="hljs-comment">//置空上传失败的状态</span><br>    &#125;<br>    ,<span class="hljs-attr">error</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>      <span class="hljs-comment">//演示失败状态，并实现重传</span><br>      <span class="hljs-keyword">var</span> demoText = $(<span class="hljs-string">&#x27;#demoText&#x27;</span>);<br>      demoText.<span class="hljs-title function_">html</span>(<span class="hljs-string">&#x27;&lt;span style=&quot;color: #FF5722;&quot;&gt;上传失败&lt;/span&gt; &lt;a class=&quot;layui-btn layui-btn-xs demo-reload&quot;&gt;重试&lt;/a&gt;&#x27;</span>);<br>      demoText.<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;.demo-reload&#x27;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;click&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>        uploadInst.<span class="hljs-title function_">upload</span>();<br>      &#125;);<br>    &#125;<br>    <span class="hljs-comment">//进度条</span><br>    ,<span class="hljs-attr">progress</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">n, elem, e</span>)&#123;<br>      element.<span class="hljs-title function_">progress</span>(<span class="hljs-string">&#x27;demo&#x27;</span>, n + <span class="hljs-string">&#x27;%&#x27;</span>); <span class="hljs-comment">//可配合 layui 进度条元素使用</span><br>      <span class="hljs-keyword">if</span>(n == <span class="hljs-number">100</span>)&#123;<br>        layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传完毕&#x27;</span>, &#123;<span class="hljs-attr">icon</span>: <span class="hljs-number">1</span>&#125;);<br>      &#125;<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//演示多文件列表</span><br>  <span class="hljs-keyword">var</span> uploadListIns = upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#testList&#x27;</span><br>    ,<span class="hljs-attr">elemList</span>: $(<span class="hljs-string">&#x27;#demoList&#x27;</span>) <span class="hljs-comment">//列表元素对象</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;https://httpbin.org/post&#x27;</span> <span class="hljs-comment">//此处用的是第三方的 http 请求演示，实际使用时改成您自己的上传接口即可。</span><br>    ,<span class="hljs-attr">accept</span>: <span class="hljs-string">&#x27;file&#x27;</span><br>    ,<span class="hljs-attr">multiple</span>: <span class="hljs-literal">true</span><br>    ,<span class="hljs-attr">number</span>: <span class="hljs-number">3</span><br>    ,<span class="hljs-attr">auto</span>: <span class="hljs-literal">false</span><br>    ,<span class="hljs-attr">bindAction</span>: <span class="hljs-string">&#x27;#testListAction&#x27;</span><br>    ,<span class="hljs-attr">choose</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>)&#123;   <br>      <span class="hljs-keyword">var</span> that = <span class="hljs-variable language_">this</span>;<br>      <span class="hljs-keyword">var</span> files = <span class="hljs-variable language_">this</span>.<span class="hljs-property">files</span> = obj.<span class="hljs-title function_">pushFile</span>(); <span class="hljs-comment">//将每次选择的文件追加到文件队列</span><br>      <span class="hljs-comment">//读取本地文件</span><br>      obj.<span class="hljs-title function_">preview</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">index, file, result</span>)&#123;<br>        <span class="hljs-keyword">var</span> tr = $([<span class="hljs-string">&#x27;&lt;tr id=&quot;upload-&#x27;</span>+ index +<span class="hljs-string">&#x27;&quot;&gt;&#x27;</span><br>          ,<span class="hljs-string">&#x27;&lt;td&gt;&#x27;</span>+ file.<span class="hljs-property">name</span> +<span class="hljs-string">&#x27;&lt;/td&gt;&#x27;</span><br>          ,<span class="hljs-string">&#x27;&lt;td&gt;&#x27;</span>+ (file.<span class="hljs-property">size</span>/<span class="hljs-number">1014</span>).<span class="hljs-title function_">toFixed</span>(<span class="hljs-number">1</span>) +<span class="hljs-string">&#x27;kb&lt;/td&gt;&#x27;</span><br>          ,<span class="hljs-string">&#x27;&lt;td&gt;&lt;div class=&quot;layui-progress&quot; lay-filter=&quot;progress-demo-&#x27;</span>+ index +<span class="hljs-string">&#x27;&quot;&gt;&lt;div class=&quot;layui-progress-bar&quot; lay-percent=&quot;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&#x27;</span><br>          ,<span class="hljs-string">&#x27;&lt;td&gt;&#x27;</span><br>            ,<span class="hljs-string">&#x27;&lt;button class=&quot;layui-btn layui-btn-xs demo-reload layui-hide&quot;&gt;重传&lt;/button&gt;&#x27;</span><br>            ,<span class="hljs-string">&#x27;&lt;button class=&quot;layui-btn layui-btn-xs layui-btn-danger demo-delete&quot;&gt;删除&lt;/button&gt;&#x27;</span><br>          ,<span class="hljs-string">&#x27;&lt;/td&gt;&#x27;</span><br>        ,<span class="hljs-string">&#x27;&lt;/tr&gt;&#x27;</span>].<span class="hljs-title function_">join</span>(<span class="hljs-string">&#x27;&#x27;</span>));<br>        <br>        <span class="hljs-comment">//单个重传</span><br>        tr.<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;.demo-reload&#x27;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;click&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>          obj.<span class="hljs-title function_">upload</span>(index, file);<br>        &#125;);<br>        <br>        <span class="hljs-comment">//删除</span><br>        tr.<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;.demo-delete&#x27;</span>).<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;click&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>          <span class="hljs-keyword">delete</span> files[index]; <span class="hljs-comment">//删除对应的文件</span><br>          tr.<span class="hljs-title function_">remove</span>();<br>          uploadListIns.<span class="hljs-property">config</span>.<span class="hljs-property">elem</span>.<span class="hljs-title function_">next</span>()[<span class="hljs-number">0</span>].<span class="hljs-property">value</span> = <span class="hljs-string">&#x27;&#x27;</span>; <span class="hljs-comment">//清空 input file 值，以免删除后出现同名文件不可选</span><br>        &#125;);<br>        <br>        that.<span class="hljs-property">elemList</span>.<span class="hljs-title function_">append</span>(tr);<br>        element.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;progress&#x27;</span>); <span class="hljs-comment">//渲染新加的进度条组件</span><br>      &#125;);<br>    &#125;<br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res, index, upload</span>)&#123; <span class="hljs-comment">//成功的回调</span><br>      <span class="hljs-keyword">var</span> that = <span class="hljs-variable language_">this</span>;<br>      <span class="hljs-comment">//if(res.code == 0)&#123; //上传成功</span><br>        <span class="hljs-keyword">var</span> tr = that.<span class="hljs-property">elemList</span>.<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;tr#upload-&#x27;</span>+ index)<br>        ,tds = tr.<span class="hljs-title function_">children</span>();<br>        tds.<span class="hljs-title function_">eq</span>(<span class="hljs-number">3</span>).<span class="hljs-title function_">html</span>(<span class="hljs-string">&#x27;&#x27;</span>); <span class="hljs-comment">//清空操作</span><br>        <span class="hljs-keyword">delete</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">files</span>[index]; <span class="hljs-comment">//删除文件队列已经上传成功的文件</span><br>        <span class="hljs-keyword">return</span>;<br>      <span class="hljs-comment">//&#125;</span><br>      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">error</span>(index, upload);<br>    &#125;<br>    ,<span class="hljs-attr">allDone</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>)&#123; <span class="hljs-comment">//多文件上传完毕后的状态回调</span><br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj)<br>    &#125;<br>    ,<span class="hljs-attr">error</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">index, upload</span>)&#123; <span class="hljs-comment">//错误回调</span><br>      <span class="hljs-keyword">var</span> that = <span class="hljs-variable language_">this</span>;<br>      <span class="hljs-keyword">var</span> tr = that.<span class="hljs-property">elemList</span>.<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;tr#upload-&#x27;</span>+ index)<br>      ,tds = tr.<span class="hljs-title function_">children</span>();<br>      tds.<span class="hljs-title function_">eq</span>(<span class="hljs-number">3</span>).<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;.demo-reload&#x27;</span>).<span class="hljs-title function_">removeClass</span>(<span class="hljs-string">&#x27;layui-hide&#x27;</span>); <span class="hljs-comment">//显示重传</span><br>    &#125;<br>    ,<span class="hljs-attr">progress</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">n, elem, e, index</span>)&#123; <span class="hljs-comment">//注意：index 参数为 layui 2.6.6 新增</span><br>      element.<span class="hljs-title function_">progress</span>(<span class="hljs-string">&#x27;progress-demo-&#x27;</span>+ index, n + <span class="hljs-string">&#x27;%&#x27;</span>); <span class="hljs-comment">//执行进度条。n 即为返回的进度百分比</span><br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//多图片上传</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test2&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">multiple</span>: <span class="hljs-literal">true</span><br>    ,<span class="hljs-attr">before</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>)&#123;<br>      <span class="hljs-comment">//预读本地文件示例，不支持ie8</span><br>      obj.<span class="hljs-title function_">preview</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">index, file, result</span>)&#123;<br>        $(<span class="hljs-string">&#x27;#demo2&#x27;</span>).<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;&lt;img src=&quot;&#x27;</span>+ result +<span class="hljs-string">&#x27;&quot; alt=&quot;&#x27;</span>+ file.<span class="hljs-property">name</span> +<span class="hljs-string">&#x27;&quot; class=&quot;layui-upload-img&quot;&gt;&#x27;</span>)<br>      &#125;);<br>    &#125;<br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      <span class="hljs-comment">//上传完毕</span><br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//指定允许上传的文件类型</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test3&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">accept</span>: <span class="hljs-string">&#x27;file&#x27;</span> <span class="hljs-comment">//普通文件</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res);<br>    &#125;<br>  &#125;);<br>  upload.<span class="hljs-title function_">render</span>(&#123; <span class="hljs-comment">//允许上传的文件后缀</span><br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test4&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">accept</span>: <span class="hljs-string">&#x27;file&#x27;</span> <span class="hljs-comment">//普通文件</span><br>    ,<span class="hljs-attr">exts</span>: <span class="hljs-string">&#x27;zip|rar|7z&#x27;</span> <span class="hljs-comment">//只允许上传压缩文件</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test5&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">accept</span>: <span class="hljs-string">&#x27;video&#x27;</span> <span class="hljs-comment">//视频</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test6&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">accept</span>: <span class="hljs-string">&#x27;audio&#x27;</span> <span class="hljs-comment">//音频</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//设定文件大小限制</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test7&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">size</span>: <span class="hljs-number">60</span> <span class="hljs-comment">//限制文件大小，单位 KB</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//同时绑定多个元素，并将属性设定在元素上</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;.demoMore&#x27;</span><br>    ,<span class="hljs-attr">before</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)&#123;<br>      layer.<span class="hljs-title function_">tips</span>(<span class="hljs-string">&#x27;接口地址：&#x27;</span>+ <span class="hljs-variable language_">this</span>.<span class="hljs-property">url</span>, <span class="hljs-variable language_">this</span>.<span class="hljs-property">item</span>, &#123;<span class="hljs-attr">tips</span>: <span class="hljs-number">1</span>&#125;);<br>    &#125;<br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res, index, upload</span>)&#123;<br>      <span class="hljs-keyword">var</span> item = <span class="hljs-variable language_">this</span>.<span class="hljs-property">item</span>;<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(item); <span class="hljs-comment">//获取当前触发上传的元素，layui 2.1.0 新增</span><br>    &#125;<br>  &#125;)<br>  <br>  <span class="hljs-comment">//选完文件后不自动上传</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test8&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">auto</span>: <span class="hljs-literal">false</span><br>    <span class="hljs-comment">//,multiple: true</span><br>    ,<span class="hljs-attr">bindAction</span>: <span class="hljs-string">&#x27;#test9&#x27;</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//拖拽上传</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test10&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;https://httpbin.org/post&#x27;</span> <span class="hljs-comment">//此处用的是第三方的 http 请求演示，实际使用时改成您自己的上传接口即可。</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      layui.$(<span class="hljs-string">&#x27;#uploadDemoView&#x27;</span>).<span class="hljs-title function_">removeClass</span>(<span class="hljs-string">&#x27;layui-hide&#x27;</span>).<span class="hljs-title function_">find</span>(<span class="hljs-string">&#x27;img&#x27;</span>).<span class="hljs-title function_">attr</span>(<span class="hljs-string">&#x27;src&#x27;</span>, res.<span class="hljs-property">files</span>.<span class="hljs-property">file</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  <br>  <span class="hljs-comment">//绑定原始文件域</span><br>  upload.<span class="hljs-title function_">render</span>(&#123;<br>    <span class="hljs-attr">elem</span>: <span class="hljs-string">&#x27;#test20&#x27;</span><br>    ,<span class="hljs-attr">url</span>: <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-comment">//此处配置你自己的上传接口即可</span><br>    ,<span class="hljs-attr">done</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>)&#123;<br>      layer.<span class="hljs-title function_">msg</span>(<span class="hljs-string">&#x27;上传成功&#x27;</span>);<br>      <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res)<br>    &#125;<br>  &#125;);<br>  <br>&#125;);<br>&lt;/script&gt;<br><br></code></pre></td></tr></table></figure><p>更多支持的参数详见下表，合理的配置它们，应对各式各样的业务需求。</p><table><thead><tr><th align="left">参数选项</th><th align="left">说明</th><th align="left">类型</th><th align="left">默认值</th></tr></thead><tbody><tr><td align="left">elem</td><td align="left">指向容器选择器，如：elem: ‘#id’。也可以是DOM对象</td><td align="left">string&#x2F;object</td><td align="left">-</td></tr><tr><td align="left">url</td><td align="left">服务端上传接口，返回的数据规范请详见下文</td><td align="left">string</td><td align="left">-</td></tr><tr><td align="left">data</td><td align="left">请求上传接口的额外参数。如：data: {id: ‘xxx’} 从 layui 2.2.6 开始，支持动态值，如:<code>&lt;/&gt;codedata: &#123;  id: function()&#123;    return $(&#39;#id&#39;).val();  &#125;&#125;</code></td><td align="left">object</td><td align="left">-</td></tr><tr><td align="left">headers</td><td align="left">接口的请求头。如：*headers: {token: ‘sasasas’}*。注：该参数为 layui 2.2.6 开始新增</td><td align="left"></td><td align="left"></td></tr><tr><td align="left">accept</td><td align="left">指定允许上传时校验的文件类型，可选值有：<em>images</em>（图片）、<em>file</em>（所有文件）、<em>video</em>（视频）、<em>audio</em>（音频）</td><td align="left">string</td><td align="left">images</td></tr><tr><td align="left">acceptMime</td><td align="left">规定打开文件选择框时，筛选出的文件类型，值为用逗号隔开的 MIME 类型列表。如： *acceptMime: ‘image&#x2F;*‘*（只显示图片文件） *acceptMime: ‘image&#x2F;jpg, image&#x2F;png’*（只显示 jpg 和 png 文件） 注：layui 2.2.6 新增</td><td align="left">string</td><td align="left">images</td></tr><tr><td align="left">exts</td><td align="left">允许上传的文件后缀。一般结合 <em>accept</em> 参数类设定。假设 accept 为 file 类型时，那么你设置 <em>exts: ‘zip|rar|7z’</em> 即代表只允许上传压缩格式的文件。如果 accept 未设定，那么限制的就是图片的文件格式</td><td align="left">string</td><td align="left">jpg|png|gif|bmp|jpeg</td></tr><tr><td align="left">auto</td><td align="left">是否选完文件后自动上传。如果设定 <em>false</em>，那么需要设置 <em>bindAction</em> 参数来指向一个其它按钮提交上传</td><td align="left">boolean</td><td align="left">true</td></tr><tr><td align="left">bindAction</td><td align="left">指向一个按钮触发上传，一般配合 auto: false 来使用。值为选择器或DOM对象，如：bindAction: ‘#btn’</td><td align="left">string&#x2F;object</td><td align="left">-</td></tr><tr><td align="left">force</td><td align="left">规定强制返回的数据格式，默认不强制。 若值为 ‘json’，则强制为 JSON 数据格式 注：layui 2.6.9 新增</td><td align="left">string</td><td align="left">null</td></tr><tr><td align="left">field</td><td align="left">设定文件域的字段名</td><td align="left">string</td><td align="left">file</td></tr><tr><td align="left">size</td><td align="left">设置文件最大可允许上传的大小，单位 KB。不支持ie8&#x2F;9</td><td align="left">number</td><td align="left">0（即不限制）</td></tr><tr><td align="left">multiple</td><td align="left">是否允许多文件上传。设置 <em>true</em>即可开启。不支持ie8&#x2F;9</td><td align="left">boolean</td><td align="left">false</td></tr><tr><td align="left">number</td><td align="left">设置同时可上传的文件数量，一般配合 multiple 参数出现。 注意：<em>该参数为 layui 2.2.3 开始新增</em></td><td align="left">number</td><td align="left">0（即不限制）</td></tr><tr><td align="left">drag</td><td align="left">是否接受拖拽的文件上传，设置 <em>false</em> 可禁用。不支持ie8&#x2F;9</td><td align="left">boolean</td><td align="left">true</td></tr><tr><td align="left">回调</td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left">choose</td><td align="left">选择文件后的回调函数。返回一个object参数，详见下文</td><td align="left">function</td><td align="left">-</td></tr><tr><td align="left">before</td><td align="left">文件提交上传前的回调。返回一个object参数（同上），详见下文</td><td align="left">function</td><td align="left">-</td></tr><tr><td align="left">done</td><td align="left">执行上传请求后的回调。返回三个参数，分别为：<em>res</em>（服务端响应信息）、<em>index</em>（当前文件的索引）、<em>upload</em>（重新上传的方法，一般在文件上传失败后使用）。详见下文</td><td align="left">function</td><td align="left">-</td></tr><tr><td align="left">error</td><td align="left">执行上传请求出现异常的回调（一般为网络异常、URL 404等）。返回两个参数，分别为：<em>index</em>（当前文件的索引）、<em>upload</em>（重新上传的方法）。详见下文</td><td align="left">function</td><td align="left">-</td></tr></tbody></table><h1 id="如何判断-JavaScript-对象是否为空"><a href="#如何判断-JavaScript-对象是否为空" class="headerlink" title="如何判断 JavaScript 对象是否为空"></a>如何判断 JavaScript 对象是否为空</h1><h2 id="Object-keys"><a href="#Object-keys" class="headerlink" title="Object.keys()"></a>Object.keys()</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">isEmpty</span>(<span class="hljs-params">obj</span>) &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">keys</span>(obj).<span class="hljs-property">length</span> === <span class="hljs-number">0</span>;<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="for…in…"><a href="#for…in…" class="headerlink" title="for…in…"></a>for…in…</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i <span class="hljs-keyword">in</span> obj) &#123; <span class="hljs-comment">// 如果不为空，则会执行到这一步，返回true</span><br>    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>&#125;<br><span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-comment">// 如果为空,返回false</span><br></code></pre></td></tr></table></figure><h2 id="JSON-stringify"><a href="#JSON-stringify" class="headerlink" title="JSON.stringify()"></a>JSON.stringify()</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">if</span> (<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(data) === <span class="hljs-string">&#x27;&#123;&#125;&#x27;</span>) &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-comment">// 如果为空,返回false</span><br>&#125;<br><span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> <span class="hljs-comment">// 如果不为空，则会执行到这一步，返回true</span><br></code></pre></td></tr></table></figure><h1 id="Json-数据解析"><a href="#Json-数据解析" class="headerlink" title="Json 数据解析"></a>Json 数据解析</h1><h3 id="JSON-parse"><a href="#JSON-parse" class="headerlink" title="JSON.parse()"></a>JSON.parse()</h3><p>JSON 通常用于与服务端交换数据。</p><p>在接收服务器数据时一般是字符串。</p><p>我们可以使用 JSON.parse() 方法将数据转换为 JavaScript 对象。</p><h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(text[, reviver])<br></code></pre></td></tr></table></figure><p><strong>参数说明：</strong></p><ul><li><strong>text:</strong> 必需， 一个有效的 JSON 字符串。</li><li><strong>reviver:</strong> 可选，一个转换结果的函数， 将为对象的每个成员调用此函数。</li></ul><hr><h2 id="JSON-解析实例"><a href="#JSON-解析实例" class="headerlink" title="JSON 解析实例"></a>JSON 解析实例</h2><p>例如我们从服务器接收了以下数据：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span> <span class="hljs-attr">&quot;name&quot;</span><span class="hljs-punctuation">:</span><span class="hljs-string">&quot;runoob&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;alexa&quot;</span><span class="hljs-punctuation">:</span><span class="hljs-number">10000</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;site&quot;</span><span class="hljs-punctuation">:</span><span class="hljs-string">&quot;www.runoob.com&quot;</span> <span class="hljs-punctuation">&#125;</span><br></code></pre></td></tr></table></figure><p>我们使用 JSON.parse() 方法处理以上数据，将其转换为 JavaScript 对象：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> obj = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(<span class="hljs-string">&#x27;&#123; &quot;name&quot;:&quot;runoob&quot;, &quot;alexa&quot;:10000, &quot;site&quot;:&quot;www.runoob.com&quot; &#125;&#x27;</span>);<br></code></pre></td></tr></table></figure><h2 id="JSON-stringify-1"><a href="#JSON-stringify-1" class="headerlink" title="JSON.stringify()"></a>JSON.stringify()</h2><p>JSON 通常用于与服务端交换数据。</p><p>在向服务器发送数据时一般是字符串。</p><p>我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。</p><h3 id="语法-1"><a href="#语法-1" class="headerlink" title="语法"></a>语法</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(value[, replacer[, space]])<br></code></pre></td></tr></table></figure><p><strong>参数说明：</strong></p><ul><li><p>value:</p><p>必需， 要转换的 JavaScript 值（通常为对象或数组）。</p></li><li><p>replacer:</p><p>可选。用于转换结果的函数或数组。</p><p>如果 replacer 为函数，则 JSON.stringify 将调用该函数，并传入每个成员的键和值。使用返回值而不是原始值。如果此函数返回 undefined，则排除成员。根对象的键是一个空字符串：””。</p><p>如果 replacer 是一个数组，则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。当 value 参数也为数组时，将忽略 replacer 数组。</p></li><li><p>space:</p><p>可选，文本添加缩进、空格和换行符，如果 space 是一个数字，则返回值文本在每个级别缩进指定数目的空格，如果 space 大于 10，则文本缩进 10 个空格。space 也可以使用非数字，如：\t。</p></li></ul><hr><h2 id="JavaScript-对象转换"><a href="#JavaScript-对象转换" class="headerlink" title="JavaScript 对象转换"></a>JavaScript 对象转换</h2><p>例如我们向服务器发送以下数据：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> obj = &#123; <span class="hljs-string">&quot;name&quot;</span>:<span class="hljs-string">&quot;runoob&quot;</span>, <span class="hljs-string">&quot;alexa&quot;</span>:<span class="hljs-number">10000</span>, <span class="hljs-string">&quot;site&quot;</span>:<span class="hljs-string">&quot;www.runoob.com&quot;</span>&#125;;<br></code></pre></td></tr></table></figure><p>我们使用 JSON.stringify() 方法处理以上数据，将其转换为字符串：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> myJSON = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(obj);<br></code></pre></td></tr></table></figure><h1 id="JavaScript-删除数组元素"><a href="#JavaScript-删除数组元素" class="headerlink" title="JavaScript 删除数组元素"></a>JavaScript 删除数组元素</h1><h2 id="splice-方法"><a href="#splice-方法" class="headerlink" title="splice() 方法"></a>splice() 方法</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> array = [<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">9</span>];<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(array);<br><br><span class="hljs-keyword">const</span> index = array.<span class="hljs-title function_">indexOf</span>(<span class="hljs-number">5</span>);<br><span class="hljs-keyword">if</span> (index &gt; -<span class="hljs-number">1</span>) &#123;<br>  array.<span class="hljs-title function_">splice</span>(index, <span class="hljs-number">1</span>); <span class="hljs-comment">// 第二个参数为删除的次数，设置只删除一次</span><br>&#125;<br><br><span class="hljs-comment">// array = [2, 9]</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(array);<br></code></pre></td></tr></table></figure><h2 id="delete-关键字"><a href="#delete-关键字" class="headerlink" title="delete 关键字"></a>delete 关键字</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> colors = [<span class="hljs-string">&quot;red&quot;</span>, <span class="hljs-string">&quot;blue&quot;</span>, <span class="hljs-string">&quot;grey&quot;</span>, <span class="hljs-string">&quot;green&quot;</span>];<br><br><span class="hljs-keyword">delete</span> colors[<span class="hljs-number">0</span>];<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(colors); <span class="hljs-comment">// [undefined, &quot;blue&quot;, &quot;grey&quot;, &quot;green&quot;]</span><br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">整理记录常用 JavaScript 业务代码，以此备忘，持续更新中...</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/JavaScript/"/>
    
    
    <category term="JavaScript" scheme="http://www.loquy.cn/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>Java 常用业务代码总结</title>
    <link href="http://www.loquy.cn/posts/3b0faab3.html"/>
    <id>http://www.loquy.cn/posts/3b0faab3.html</id>
    <published>2022-06-10T03:13:27.000Z</published>
    <updated>2023-12-22T06:37:30.965Z</updated>
    
    <content type="html"><![CDATA[<h1 id="遍历文件夹下的所有文件"><a href="#遍历文件夹下的所有文件" class="headerlink" title="遍历文件夹下的所有文件"></a>遍历文件夹下的所有文件</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ArrayList&lt;File&gt; <span class="hljs-title function_">readFiles</span><span class="hljs-params">(File file)</span>&#123;<br>    ArrayList&lt;File&gt; list = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>    File[] fs = file.listFiles();<br>    <span class="hljs-keyword">assert</span> fs != <span class="hljs-literal">null</span>;<br>    <span class="hljs-keyword">for</span> (File f : fs) &#123;<br>        <span class="hljs-comment">// 若是目录，则递归读取</span><br>        <span class="hljs-keyword">if</span> (f.isDirectory()) &#123;<br>            readFiles(f);<br>        &#125;<br>        <span class="hljs-comment">// 若是文件，添加到集合</span><br>        <span class="hljs-keyword">if</span> (f.isFile()) &#123;<br>            list.add(f);<br>        &#125;<br>    &#125;<br>    <span class="hljs-keyword">return</span> list;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="导出Excel"><a href="#导出Excel" class="headerlink" title="导出Excel"></a>导出Excel</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">exportData</span><span class="hljs-params">(List&lt;Map&lt;String, Object&gt;&gt; data, Map&lt;String, String&gt; headerMap, String title, HttpServletResponse response)</span> &#123;<br>    <span class="hljs-comment">// 通过工具类创建writer，默认创建xls格式</span><br>    <span class="hljs-type">ExcelWriter</span> <span class="hljs-variable">writer</span> <span class="hljs-operator">=</span> ExcelUtil.getWriter();<br>    writer.merge(headerMap.size() - <span class="hljs-number">1</span>, title);<br>    <span class="hljs-keyword">for</span> (Map&lt;String, Object&gt; stringObjectMap : data) &#123;<br>        List&lt;String&gt; removeKeys = <span class="hljs-keyword">new</span> <span class="hljs-title class_">LinkedList</span>&lt;&gt;();<br>        <span class="hljs-keyword">for</span> (String stringObjectKey : stringObjectMap.keySet()) &#123;<br>            <span class="hljs-keyword">if</span> (!headerMap.containsKey(stringObjectKey)) &#123;<br>                removeKeys.add(stringObjectKey);<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">for</span> (String removeKey : removeKeys) &#123;<br>            stringObjectMap.remove(removeKey);<br>        &#125;<br>    &#125;<br>    writer.setHeaderAlias(headerMap);<br>    <span class="hljs-comment">// 一次性写出内容，使用默认样式，强制输出标题</span><br>    writer.write(data, <span class="hljs-literal">true</span>);<br>    <span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;<br>    <span class="hljs-keyword">while</span> (i &lt; data.size()) &#123;<br>        <span class="hljs-comment">//自动宽度</span><br>        writer.autoSizeColumn(i);<br>        i++;<br>    &#125;<br>    <span class="hljs-comment">//out为OutputStream，需要写出到的目标流</span><br>    <span class="hljs-comment">//response为HttpServletResponse对象</span><br>    response.setContentType(<span class="hljs-string">&quot;application/vnd.ms-excel;charset=utf-8&quot;</span>);<br>    <span class="hljs-comment">//devices.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码</span><br>    <span class="hljs-keyword">try</span> &#123;<br>        response.setHeader(<span class="hljs-string">&quot;Content-Disposition&quot;</span>, <span class="hljs-string">&quot;attachment;filename=&quot;</span> + URLEncoder.encode(title + <span class="hljs-string">&quot;.xls&quot;</span>, <span class="hljs-string">&quot;utf-8&quot;</span>));<br>    &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>        e.printStackTrace();<br>    &#125;<br>    <span class="hljs-type">ServletOutputStream</span> <span class="hljs-variable">out</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;<br>    <span class="hljs-keyword">try</span> &#123;<br>        out = response.getOutputStream();<br>    &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>        e.printStackTrace();<br>    &#125;<br>    writer.flush(out);<br>    <span class="hljs-comment">// 关闭writer，释放内存</span><br>    writer.close();<br>    <span class="hljs-comment">//此处记得关闭输出Servlet流</span><br>    IoUtil.close(out);<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="接口接收-Json-数组对象"><a href="#接口接收-Json-数组对象" class="headerlink" title="接口接收 Json 数组对象"></a>接口接收 Json 数组对象</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@PostMapping(&quot;example&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">example</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> List&lt;exampleDto&gt; exampleDtoList)</span> &#123;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="接口通用返回泛型数据的格式"><a href="#接口通用返回泛型数据的格式" class="headerlink" title="接口通用返回泛型数据的格式"></a>接口通用返回泛型数据的格式</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@ApiModel(value = &quot;通用返回格式&quot;)</span><br><span class="hljs-meta">@Data</span><br><span class="hljs-meta">@NoArgsConstructor</span><br><span class="hljs-meta">@AllArgsConstructor</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ResultModel</span>&lt;T&gt; <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">long</span> <span class="hljs-variable">serialVersionUID</span> <span class="hljs-operator">=</span> <span class="hljs-number">1L</span>;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;返回状态码（0成功，-1失败）&quot;)</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> code;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;返回消息&quot;)</span><br>    <span class="hljs-keyword">public</span> String message;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;返回数据&quot;)</span><br>    <span class="hljs-keyword">public</span> T data;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>&lt;T&gt; ResultModel&lt;T&gt; <span class="hljs-title function_">success</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResultModel</span>&lt;&gt;(ResultEnums.SUCCESS.getCode(), ResultEnums.SUCCESS.getMessage(), <span class="hljs-literal">null</span>);<br>    &#125;<br><br> <br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>&lt;T&gt; ResultModel&lt;T&gt; <span class="hljs-title function_">success</span><span class="hljs-params">(T data)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResultModel</span>&lt;&gt;(ResultEnums.SUCCESS.getCode(), ResultEnums.SUCCESS.getMessage(), data);<br>    &#125;<br><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>&lt;T&gt; ResultModel&lt;T&gt; <span class="hljs-title function_">success</span><span class="hljs-params">(T data, String message)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResultModel</span>&lt;&gt;(ResultEnums.SUCCESS.getCode(), message, data);<br>    &#125;<br><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>&lt;T&gt; ResultModel&lt;T&gt; <span class="hljs-title function_">fail</span><span class="hljs-params">(String message)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResultModel</span>&lt;&gt;(ResultEnums.FAIL.getCode(), message, <span class="hljs-literal">null</span>);<br>    &#125;<br><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>&lt;T&gt; ResultModel&lt;T&gt; <span class="hljs-title function_">fail</span><span class="hljs-params">(<span class="hljs-type">int</span> code, String message)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResultModel</span>&lt;&gt;(code, message, <span class="hljs-literal">null</span>);<br>    &#125;<br><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>&lt;T&gt; ResultModel&lt;T&gt; <span class="hljs-title function_">fail</span><span class="hljs-params">(<span class="hljs-type">int</span> code, String message, T data)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResultModel</span>&lt;&gt;(code, message, data);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="开启定时任务"><a href="#开启定时任务" class="headerlink" title="开启定时任务"></a>开启定时任务</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.cron;<br><br><span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.EnableScheduling;<br><span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.Scheduled;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><br><span class="hljs-meta">@Component</span><br><span class="hljs-meta">@EnableScheduling</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">exampleCron</span> &#123;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 每天凌晨执行一次</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Scheduled(cron = &quot;1 * * * * ?&quot;)</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">example</span><span class="hljs-params">()</span> &#123;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="开启事务"><a href="#开启事务" class="headerlink" title="开启事务"></a>开启事务</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Transactional(rollbackFor = Exception.class)</span><br></code></pre></td></tr></table></figure><h1 id="判断多个线程结束"><a href="#判断多个线程结束" class="headerlink" title="判断多个线程结束"></a>判断多个线程结束</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">threadIsOver</span><span class="hljs-params">(ArrayList&lt;SearchByTime&gt; threads, <span class="hljs-type">long</span> start)</span>&#123;<br>    <span class="hljs-type">int</span> <span class="hljs-variable">size</span> <span class="hljs-operator">=</span> threads.size();<br>    HashSet&lt;Object&gt; died = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashSet</span>&lt;&gt;();<br>    <span class="hljs-keyword">do</span> &#123;<br>        <span class="hljs-keyword">for</span> (SearchByTime thread : threads) &#123;<br>            <span class="hljs-keyword">if</span> (!thread.isAlive()) &#123;<br>                died.add(thread.getId());<br>            &#125;<br>        &#125;<br>    &#125; <span class="hljs-keyword">while</span> (size != died.size());<br>    <span class="hljs-type">long</span> <span class="hljs-variable">end</span> <span class="hljs-operator">=</span> System.currentTimeMillis();<br>    System.out.println(<span class="hljs-string">&quot;\033[42m所有线程执行完毕&quot;</span> +<br>                       <span class="hljs-string">&quot;，线程数：&quot;</span>+ size +<br>                       <span class="hljs-string">&quot;，用时: &quot;</span> + (end - start) / <span class="hljs-number">1000</span> + <span class="hljs-string">&quot;s&quot;</span> + <span class="hljs-string">&quot;\033[0m&quot;</span><br>                      );<br>&#125;<br></code></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.thread;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SearchByTime</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Thread</span> &#123;<br>    <br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">run</span><span class="hljs-params">()</span> &#123;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="请求接口"><a href="#请求接口" class="headerlink" title="请求接口"></a>请求接口</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> JSONArray <span class="hljs-title function_">get</span><span class="hljs-params">(String apiFrom, String startTime, String endTime, String timeType)</span> &#123;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">baseUrl</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span>;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">url</span> <span class="hljs-operator">=</span> baseUrl + apiFrom<br>        + <span class="hljs-string">&quot;?start_time=&quot;</span> + startTime + <span class="hljs-string">&quot;&amp;&quot;</span><br>        + <span class="hljs-string">&quot;end_time=&quot;</span> + endTime + <span class="hljs-string">&quot;&amp;&quot;</span><br>        + <span class="hljs-string">&quot;time_type=&quot;</span> + timeType;<br>    url = url.replaceAll(<span class="hljs-string">&quot; &quot;</span>, <span class="hljs-string">&quot;%20&quot;</span>);<br>    <span class="hljs-type">HttpResponse</span> <span class="hljs-variable">response</span> <span class="hljs-operator">=</span> HttpRequest.get(url)<br>        .header(<span class="hljs-string">&quot;charset&quot;</span>, <span class="hljs-string">&quot;UTF-8&quot;</span>)<br>        .timeout(<span class="hljs-number">60000</span> * <span class="hljs-number">5</span>)<br>        .execute();<br>    <span class="hljs-type">JSONObject</span> <span class="hljs-variable">jsonObject</span> <span class="hljs-operator">=</span> JSONObject.parseObject(response.body());<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">code</span> <span class="hljs-operator">=</span> jsonObject.get(<span class="hljs-string">&quot;code&quot;</span>);<br>    <span class="hljs-type">String</span> <span class="hljs-variable">msg</span> <span class="hljs-operator">=</span> (String) jsonObject.get(<span class="hljs-string">&quot;msg&quot;</span>);<br>    <span class="hljs-type">JSONArray</span> <span class="hljs-variable">data</span> <span class="hljs-operator">=</span> jsonObject.getJSONArray(<span class="hljs-string">&quot;result&quot;</span>);<br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">successCode</span> <span class="hljs-operator">=</span> <span class="hljs-number">2000</span>;<br>    <span class="hljs-keyword">if</span> (!successCode.equals(code)) &#123;<br>        logger.info(msg + <span class="hljs-string">&quot;\n获取接口数据失败，接口地址：&quot;</span> + url);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">JSONArray</span>();<br>    &#125;<br>    <span class="hljs-keyword">return</span> data;<br>&#125;<br></code></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">private</span> JSONArray <span class="hljs-title function_">post</span><span class="hljs-params">(String token)</span> &#123;<br>    <span class="hljs-type">JSONObject</span> <span class="hljs-variable">params</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">JSONObject</span>();<br>    params.put(<span class="hljs-string">&quot;pageSize&quot;</span>, <span class="hljs-number">1000</span>);<br>    params.put(<span class="hljs-string">&quot;currentPage&quot;</span>, currentPage);<br>    <span class="hljs-type">HttpResponse</span> <span class="hljs-variable">response</span> <span class="hljs-operator">=</span> HttpRequest.post(baseUrl + <span class="hljs-string">&quot;xx&quot;</span>)<br>        .header(<span class="hljs-string">&quot;Content-Type&quot;</span>, <span class="hljs-string">&quot;application/json&quot;</span>)<br>        .header(<span class="hljs-string">&quot;charset&quot;</span>, <span class="hljs-string">&quot;UTF-8&quot;</span>)<br>        .header(<span class="hljs-string">&quot;Authorization&quot;</span>, token)<br>        .body(params.toJSONString())<br>        .execute();<br><br>    <span class="hljs-type">JSONObject</span> <span class="hljs-variable">JsonObject</span> <span class="hljs-operator">=</span> JSONObject.parseObject(response.body());<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">code</span> <span class="hljs-operator">=</span> JsonObject.get(<span class="hljs-string">&quot;code&quot;</span>);<br>    <span class="hljs-type">JSONArray</span> <span class="hljs-variable">data</span> <span class="hljs-operator">=</span> JsonObject.getJSONArray(<span class="hljs-string">&quot;data&quot;</span>);<br>    <span class="hljs-keyword">if</span> (!successCode.equals(code)) &#123;<br>        logger.info(<span class="hljs-string">&quot;获取接口数据失败&quot;</span>);<br>    &#125;<br>    <span class="hljs-keyword">return</span> data;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="文件上传下载"><a href="#文件上传下载" class="headerlink" title="文件上传下载"></a>文件上传下载</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.controller;<br><br><span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;<br><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;<br><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;<br><span class="hljs-keyword">import</span> org.springframework.web.multipart.commons.CommonsMultipartFile;<br><br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;<br><span class="hljs-keyword">import</span> java.io.*;<br><span class="hljs-keyword">import</span> java.net.URLEncoder;<br><br><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileController</span> &#123;<br><br>    <span class="hljs-comment">//@RequestParam(&quot;file&quot;) 将name=file控件得到的文件封装成CommonsMultipartFile 对象</span><br>    <span class="hljs-comment">//批量上传CommonsMultipartFile则为数组即可</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/upload&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">fileUpload</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(&quot;file&quot;)</span> CommonsMultipartFile file , HttpServletRequest request)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br><br>        <span class="hljs-comment">//获取文件名 : file.getOriginalFilename();</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">uploadFileName</span> <span class="hljs-operator">=</span> file.getOriginalFilename();<br><br>        <span class="hljs-comment">//如果文件名为空，直接回到首页！</span><br>        <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;&quot;</span>.equals(uploadFileName))&#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;redirect:/index.jsp&quot;</span>;<br>        &#125;<br>        System.out.println(<span class="hljs-string">&quot;上传文件名 : &quot;</span>+uploadFileName);<br><br>        <span class="hljs-comment">//上传路径保存设置</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> request.getServletContext().getRealPath(<span class="hljs-string">&quot;/upload&quot;</span>);<br>        <span class="hljs-comment">//如果路径不存在，创建一个</span><br>        <span class="hljs-type">File</span> <span class="hljs-variable">realPath</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path);<br>        <span class="hljs-keyword">if</span> (!realPath.exists())&#123;<br>            realPath.mkdir();<br>        &#125;<br>        System.out.println(<span class="hljs-string">&quot;上传文件保存地址：&quot;</span>+realPath);<br><br>        <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> file.getInputStream(); <span class="hljs-comment">//文件输入流</span><br>        <span class="hljs-type">OutputStream</span> <span class="hljs-variable">os</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(realPath,uploadFileName)); <span class="hljs-comment">//文件输出流</span><br><br>        <span class="hljs-comment">//读取写出</span><br>        <span class="hljs-type">int</span> len=<span class="hljs-number">0</span>;<br>        <span class="hljs-type">byte</span>[] buffer = <span class="hljs-keyword">new</span> <span class="hljs-title class_">byte</span>[<span class="hljs-number">1024</span>];<br>        <span class="hljs-keyword">while</span> ((len=is.read(buffer))!=-<span class="hljs-number">1</span>)&#123;<br>            os.write(buffer,<span class="hljs-number">0</span>,len);<br>            os.flush();<br>        &#125;<br>        os.close();<br>        is.close();<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;redirect:/index.jsp&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-comment">/*</span><br><span class="hljs-comment">     * 采用file.Transto 来保存上传的文件</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/upload2&quot;)</span><br>    <span class="hljs-keyword">public</span> String  <span class="hljs-title function_">fileUpload2</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(&quot;file&quot;)</span> CommonsMultipartFile file, HttpServletRequest request)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br><br>        <span class="hljs-comment">//上传路径保存设置</span><br>        <span class="hljs-type">String</span> <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> request.getServletContext().getRealPath(<span class="hljs-string">&quot;/upload&quot;</span>);<br>        <span class="hljs-type">File</span> <span class="hljs-variable">realPath</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path);<br>        <span class="hljs-keyword">if</span> (!realPath.exists())&#123;<br>            realPath.mkdir();<br>        &#125;<br>        <span class="hljs-comment">//上传文件地址</span><br>        System.out.println(<span class="hljs-string">&quot;上传文件保存地址：&quot;</span>+realPath);<br><br>        <span class="hljs-comment">//通过CommonsMultipartFile的方法直接写文件（注意这个时候）</span><br>        file.transferTo(<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(realPath +<span class="hljs-string">&quot;/&quot;</span>+ file.getOriginalFilename()));<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;redirect:/index.jsp&quot;</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@RequestMapping(value=&quot;/download&quot;)</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">downloads</span><span class="hljs-params">(HttpServletResponse response , HttpServletRequest request)</span> <span class="hljs-keyword">throws</span> Exception&#123;<br>        <span class="hljs-comment">//要下载的图片地址</span><br>        <span class="hljs-type">String</span>  <span class="hljs-variable">path</span> <span class="hljs-operator">=</span> request.getServletContext().getRealPath(<span class="hljs-string">&quot;/static&quot;</span>);<br>        <span class="hljs-type">String</span>  <span class="hljs-variable">fileName</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;1.jpg&quot;</span>;<br>        System.out.println(path);<br>        <span class="hljs-comment">//1、设置response 响应头</span><br>        response.reset(); <span class="hljs-comment">//设置页面不缓存,清空buffer</span><br>        response.setCharacterEncoding(<span class="hljs-string">&quot;UTF-8&quot;</span>); <span class="hljs-comment">//字符编码</span><br>        response.setContentType(<span class="hljs-string">&quot;multipart/form-data&quot;</span>); <span class="hljs-comment">//二进制传输数据</span><br>        <span class="hljs-comment">//设置响应头</span><br>        response.setHeader(<span class="hljs-string">&quot;Content-Disposition&quot;</span>,<br>                <span class="hljs-string">&quot;attachment;fileName=&quot;</span>+ URLEncoder.encode(fileName, <span class="hljs-string">&quot;UTF-8&quot;</span>));<br><br>        <span class="hljs-type">File</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(path,fileName);<br>        <span class="hljs-comment">//2、 读取文件--输入流</span><br>        InputStream input=<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(file);<br>        <span class="hljs-comment">//3、 写出文件--输出流</span><br>        <span class="hljs-type">OutputStream</span> <span class="hljs-variable">out</span> <span class="hljs-operator">=</span> response.getOutputStream();<br><br>        <span class="hljs-type">byte</span>[] buff =<span class="hljs-keyword">new</span> <span class="hljs-title class_">byte</span>[<span class="hljs-number">1024</span>];<br>        <span class="hljs-type">int</span> index=<span class="hljs-number">0</span>;<br>        <span class="hljs-comment">//4、执行 写出操作</span><br>        <span class="hljs-keyword">while</span>((index= input.read(buff))!= -<span class="hljs-number">1</span>)&#123;<br>            out.write(buff, <span class="hljs-number">0</span>, index);<br>            out.flush();<br>        &#125;<br>        out.close();<br>        input.close();<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="自动生成接口文档"><a href="#自动生成接口文档" class="headerlink" title="自动生成接口文档"></a>自动生成接口文档</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Swagger2的接口配置</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@EnableSwagger2</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SwaggerConfig</span><br>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 创建API</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-keyword">public</span> Docket <span class="hljs-title function_">createRestApi</span><span class="hljs-params">()</span><br>    &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Docket</span>(DocumentationType.SWAGGER_2)<br>                <span class="hljs-comment">// 详细定制</span><br>                .apiInfo(apiInfo())<br>                .select()<br>                <span class="hljs-comment">// 指定当前包路径</span><br>                .apis(RequestHandlerSelectors.basePackage(<span class="hljs-string">&quot;com.example.app.api&quot;</span>))<br>                <span class="hljs-comment">// 扫描所有 .apis(RequestHandlerSelectors.any())</span><br>                .paths(PathSelectors.any())<br>                .build();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 添加摘要信息</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> ApiInfo <span class="hljs-title function_">apiInfo</span><span class="hljs-params">()</span><br>    &#123;<br>        <span class="hljs-comment">// 用ApiInfoBuilder进行定制</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ApiInfoBuilder</span>()<br>                .title(<span class="hljs-string">&quot;标题&quot;</span>)<br>                .description(<span class="hljs-string">&quot;描述&quot;</span>)<br>                .version(<span class="hljs-string">&quot;版本号:1.01&quot;</span>)<br>                .build();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="Bean-和-Map-的转换"><a href="#Bean-和-Map-的转换" class="headerlink" title="Bean 和 Map 的转换"></a>Bean 和 Map 的转换</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.fjzxdz.ams.<span class="hljs-keyword">module</span>.wryzl.utils;<br><br><span class="hljs-keyword">import</span> org.springframework.cglib.beans.BeanMap;<br><br><span class="hljs-keyword">import</span> java.util.HashMap;<br><span class="hljs-keyword">import</span> java.util.Map;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">HashMapUtils</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-type">int</span> <span class="hljs-title function_">calculateInitialCapacity</span><span class="hljs-params">(<span class="hljs-type">int</span> expectedSize)</span> &#123;<br>        <span class="hljs-keyword">return</span> (<span class="hljs-type">int</span>) ((expectedSize / <span class="hljs-number">0.75</span>) + <span class="hljs-number">1</span>);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> &lt;T&gt; Map&lt;String, Object&gt; <span class="hljs-title function_">beanToMap</span><span class="hljs-params">(T bean)</span> &#123;<br>        Map&lt;String, Object&gt; map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(<span class="hljs-number">16</span>);<br>        <span class="hljs-keyword">if</span> (bean != <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-type">BeanMap</span> <span class="hljs-variable">beanMap</span> <span class="hljs-operator">=</span> BeanMap.create(bean);<br>            <span class="hljs-keyword">for</span> (Object key : beanMap.keySet()) &#123;<br>                map.put(key + <span class="hljs-string">&quot;&quot;</span>, beanMap.get(key));<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">return</span> map;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> &lt;T&gt; T <span class="hljs-title function_">mapToBean</span><span class="hljs-params">(Map&lt;String, Object&gt; map, Class&lt;T&gt; clazz)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">T</span> <span class="hljs-variable">bean</span> <span class="hljs-operator">=</span> clazz.newInstance();<br>        <span class="hljs-type">BeanMap</span> <span class="hljs-variable">beanMap</span> <span class="hljs-operator">=</span> BeanMap.create(bean);<br>        beanMap.putAll(map);<br>        <span class="hljs-keyword">return</span> bean;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="Oracle中分页查询语句"><a href="#Oracle中分页查询语句" class="headerlink" title="Oracle中分页查询语句"></a>Oracle中分页查询语句</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> HashMap&lt;String, Object&gt; <span class="hljs-title function_">getPageList</span><span class="hljs-params">(String listSql, String page, String pageSize)</span> &#123;<br>    List&lt;HashMap&lt;String, Object&gt;&gt; list = simpleDao.getNativeQueryList(<span class="hljs-string">&quot;SELECT\n&quot;</span> +<br>            <span class="hljs-string">&quot;\t* \n&quot;</span> +<br>            <span class="hljs-string">&quot;FROM\n&quot;</span> +<br>            <span class="hljs-string">&quot;\t(\n&quot;</span> +<br>            <span class="hljs-string">&quot;SELECT\n&quot;</span> +<br>            <span class="hljs-string">&quot;\ta.*,\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tROWNUM rn \n&quot;</span> +<br>            <span class="hljs-string">&quot;FROM\n&quot;</span> +<br>            <span class="hljs-string">&quot;\t(\n&quot;</span> + listSql +<br>            <span class="hljs-string">&quot;\t) a \n&quot;</span> +<br>            <span class="hljs-string">&quot;\t) \n&quot;</span> +<br>            <span class="hljs-string">&quot;WHERE\n&quot;</span> +<br>            <span class="hljs-string">&quot;\trn &gt; ( &quot;</span> + page + <span class="hljs-string">&quot; - 1 ) * &quot;</span> + pageSize + <span class="hljs-string">&quot; \n&quot;</span> +<br>            <span class="hljs-string">&quot;\tAND rn &lt;= ( &quot;</span> + page + <span class="hljs-string">&quot; ) * &quot;</span> + pageSize + <span class="hljs-string">&quot;&quot;</span>);<br><br>    List&lt;HashMap&lt;String, Object&gt;&gt; countList = simpleDao.getNativeQueryList(<span class="hljs-string">&quot;SELECT\n&quot;</span> +<br>            <span class="hljs-string">&quot;\tcount( * ) total\n&quot;</span> +<br>            <span class="hljs-string">&quot;FROM\n&quot;</span> +<br>            <span class="hljs-string">&quot;\t(\n&quot;</span> + listSql +<br>            <span class="hljs-string">&quot;\t)&quot;</span>);<br><br>    HashMap&lt;String, Object&gt; map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;(HashMapUtils.calculateInitialCapacity(<span class="hljs-number">4</span>));<br>    map.put(<span class="hljs-string">&quot;list&quot;</span>, list);<br>    map.put(<span class="hljs-string">&quot;total&quot;</span>, countList.size() &gt; <span class="hljs-number">0</span> ? countList.get(<span class="hljs-number">0</span>).get(<span class="hljs-string">&quot;total&quot;</span>) : <span class="hljs-number">0</span>);<br>    map.put(<span class="hljs-string">&quot;page&quot;</span>, Integer.valueOf(page));<br>    map.put(<span class="hljs-string">&quot;pageSize&quot;</span>, Integer.valueOf(pageSize));<br><br>    <span class="hljs-keyword">return</span> map;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="构造树形结构"><a href="#构造树形结构" class="headerlink" title="构造树形结构"></a>构造树形结构</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><span class="hljs-keyword">import</span> java.util.UUID;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TreeEntity</span> &#123;<br>    <span class="hljs-keyword">private</span> String uuid;<br>    <span class="hljs-keyword">private</span> String pid;<br>    <span class="hljs-keyword">private</span> List&lt;TreeEntity&gt; children;<br>    <span class="hljs-keyword">private</span> Object value;<br>    <span class="hljs-keyword">private</span> String name;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">TreeEntity</span><span class="hljs-params">(String pid, Object value, String name)</span> &#123;<br>        <span class="hljs-built_in">this</span>.uuid = UUID.randomUUID().toString();<br>        <span class="hljs-built_in">this</span>.pid = pid;<br>        <span class="hljs-built_in">this</span>.children = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        <span class="hljs-built_in">this</span>.value = value;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getUuid</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> uuid;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setUuid</span><span class="hljs-params">(String uuid)</span> &#123;<br>        <span class="hljs-built_in">this</span>.uuid = uuid;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getPid</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> pid;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setPid</span><span class="hljs-params">(String pid)</span> &#123;<br>        <span class="hljs-built_in">this</span>.pid = pid;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> List&lt;TreeEntity&gt; <span class="hljs-title function_">getChildren</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> children;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setChildren</span><span class="hljs-params">(List&lt;TreeEntity&gt; children)</span> &#123;<br>        <span class="hljs-built_in">this</span>.children = children;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> Object <span class="hljs-title function_">getValue</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> value;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setValue</span><span class="hljs-params">(Object value)</span> &#123;<br>        <span class="hljs-built_in">this</span>.value = value;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> &#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">addChild</span><span class="hljs-params">(TreeEntity child)</span> &#123;<br>        children.add(child);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">removeChild</span><span class="hljs-params">(TreeEntity child)</span> &#123;<br>        children.remove(child);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><code class="hljs java"><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;TreeEntity&gt; <span class="hljs-title function_">buildTree</span><span class="hljs-params">(List&lt;TreeEntity&gt; nodes, <span class="hljs-type">boolean</span> isSearch)</span> &#123;<br>    <span class="hljs-keyword">if</span> (isSearch) &#123;<br>        <span class="hljs-comment">// 遍历节点，将uuid添加到nodeIds中</span><br>        Set&lt;String&gt; nodeIds = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashSet</span>&lt;&gt;();<br>        <span class="hljs-keyword">for</span> (TreeEntity node : nodes) &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">nodeId</span> <span class="hljs-operator">=</span> node.getUuid();<br>            nodeIds.add(nodeId);<br>        &#125;<br><br>        <span class="hljs-comment">// 找到所有没有父节点的节点，并将它们的pid设置为null</span><br>        <span class="hljs-keyword">for</span> (TreeEntity node : nodes) &#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">pid</span> <span class="hljs-operator">=</span> node.getPid();<br>            <span class="hljs-keyword">if</span> (pid != <span class="hljs-literal">null</span> &amp;&amp; !nodeIds.contains(pid)) &#123;<br>                node.setPid(<span class="hljs-literal">null</span>);<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">// 按照pid进行分组，然后递归构造树</span><br>    Map&lt;String, List&lt;TreeEntity&gt;&gt; map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;();<br>    <span class="hljs-keyword">for</span> (TreeEntity node : nodes) &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">pid</span> <span class="hljs-operator">=</span> node.getPid();<br>        List&lt;TreeEntity&gt; group = map.computeIfAbsent(pid, k -&gt; <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;());<br>        group.add(node);<br>    &#125;<br><br>    List&lt;TreeEntity&gt; roots = map.get(<span class="hljs-literal">null</span>);<br>    <span class="hljs-keyword">if</span> (roots != <span class="hljs-literal">null</span>) &#123;<br>        <span class="hljs-keyword">for</span> (TreeEntity root : roots) &#123;<br>            buildSubTree(root, map);<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">return</span> roots;<br>&#125;<br><br><br><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">buildSubTree</span><span class="hljs-params">(TreeEntity node, Map&lt;String, List&lt;TreeEntity&gt;&gt; map)</span> &#123;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">nodeId</span> <span class="hljs-operator">=</span> node.getUuid();<br>    node.setValue(node.getUuid());<br>    List&lt;TreeEntity&gt; children = map.get(nodeId);<br>    node.setChildren(children);<br><br>    <span class="hljs-keyword">if</span> (children != <span class="hljs-literal">null</span>) &#123;<br>        <span class="hljs-keyword">for</span> (TreeEntity child : children) &#123;<br>            buildSubTree(child, map);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h1 id="读取目录的所有文件后逐行写入新的文件"><a href="#读取目录的所有文件后逐行写入新的文件" class="headerlink" title="读取目录的所有文件后逐行写入新的文件"></a>读取目录的所有文件后逐行写入新的文件</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.*;<br><span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ReadFiles</span> &#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br><br>        <span class="hljs-type">File</span> <span class="hljs-variable">fileE</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;H:\\test.txt&quot;</span>);<br><br>        <span class="hljs-keyword">if</span> (fileE.exists()) &#123;<br>            <span class="hljs-type">boolean</span> <span class="hljs-variable">delete</span> <span class="hljs-operator">=</span> fileE.delete();<br>            System.out.println(delete);<br>        &#125;<br><br>        <span class="hljs-type">File</span> <span class="hljs-variable">file</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;H:\\&quot;</span>);<br><br>        <span class="hljs-type">File</span> <span class="hljs-variable">writerFile</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>(<span class="hljs-string">&quot;H:\\test.txt&quot;</span>);<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">boolean</span> <span class="hljs-variable">newFile</span> <span class="hljs-operator">=</span> writerFile.createNewFile();<br>            System.out.println(newFile);<br>        &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>            e.printStackTrace();<br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br>        readFiles(file, writerFile);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">readFiles</span><span class="hljs-params">(File file, File writerFile)</span> &#123;<br>        File[] fs = file.listFiles();<br>        <span class="hljs-keyword">assert</span> fs != <span class="hljs-literal">null</span>;<br>        <span class="hljs-keyword">for</span> (File f : fs) &#123;<br>            <span class="hljs-comment">// 若是目录，则递归读取</span><br>            <span class="hljs-keyword">if</span> (f.isDirectory()) &#123;<br>                readFiles(f, writerFile);<br>            &#125;<br>            <span class="hljs-comment">// 不是 java 后缀跳过</span><br>            <span class="hljs-type">String</span> <span class="hljs-variable">suffix</span> <span class="hljs-operator">=</span> f.getName().substring(f.getName().lastIndexOf(<span class="hljs-string">&quot;.&quot;</span>) + <span class="hljs-number">1</span>);<br>            <span class="hljs-keyword">if</span> (!<span class="hljs-string">&quot;java&quot;</span>.equals(suffix)) &#123;<br>                <span class="hljs-keyword">continue</span>;<br>            &#125;<br>            <span class="hljs-keyword">if</span> (f.isFile()) &#123;<br>                <span class="hljs-keyword">try</span> &#123;<br>                    readAndWriterFile(f, writerFile);<br>                &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>                    e.printStackTrace();<br>                &#125;<br>            &#125;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">readAndWriterFile</span><span class="hljs-params">(File f, File writerFile)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br>        BufferedReader br;<br>        br = <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedReader</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileReader</span>(f.getPath()));<br>        String con;<br>        <span class="hljs-type">FileOutputStream</span> <span class="hljs-variable">fop</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutputStream</span>(writerFile, <span class="hljs-literal">true</span>);<br>        <span class="hljs-type">OutputStreamWriter</span> <span class="hljs-variable">writer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">OutputStreamWriter</span>(fop, StandardCharsets.UTF_8);<br>        <span class="hljs-comment">// 逐行读取</span><br>        <span class="hljs-keyword">while</span> ((con = br.readLine()) != <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-comment">// 跳过空行</span><br>            <span class="hljs-keyword">if</span> (!<span class="hljs-string">&quot;&quot;</span>.equals(con)) &#123;<br>                <span class="hljs-type">boolean</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;<br>                <span class="hljs-comment">// 跳过tab</span><br>                <span class="hljs-keyword">if</span> (con.length() == <span class="hljs-number">1</span>) &#123;<br>                    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i &lt; con.length(); i++) &#123;<br>                        <span class="hljs-type">char</span> <span class="hljs-variable">c</span> <span class="hljs-operator">=</span> con.charAt(i);<br>                        <span class="hljs-keyword">if</span> (<span class="hljs-string">&#x27;\t&#x27;</span> == c) &#123;<br>                            is = <span class="hljs-literal">true</span>;<br>                            <span class="hljs-keyword">break</span>;<br>                        &#125;<br>                    &#125;<br>                &#125;<br>                <span class="hljs-keyword">if</span> (!is) &#123;<br>                    System.out.println(con);<br>                    writer.append(con);<br>                    writer.append(<span class="hljs-string">&quot;\n&quot;</span>);<br>                &#125;<br>            &#125;<br>        &#125;<br>        writer.close();<br>        fop.close();<br>        br.close();<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure><h1 id="常用字符串操作"><a href="#常用字符串操作" class="headerlink" title="常用字符串操作"></a>常用字符串操作</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.example.demo.utils;<br><br><span class="hljs-keyword">import</span> org.apache.commons.lang3.StringUtils;<br><span class="hljs-keyword">import</span> org.apache.commons.lang3.time.DateUtils;<br><br><span class="hljs-keyword">import</span> java.text.ParseException;<br><span class="hljs-keyword">import</span> java.util.Date;<br><span class="hljs-keyword">import</span> java.util.Random;<br><span class="hljs-keyword">import</span> java.util.regex.Matcher;<br><span class="hljs-keyword">import</span> java.util.regex.Pattern;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The type Common String utils.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> loquy</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CommonStringUtils</span> &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String[] IS_DATE_PATTERNS = &#123;<br>            <span class="hljs-string">&quot;yyyy-MM-dd&quot;</span>, <span class="hljs-string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>, <span class="hljs-string">&quot;yyyy-MM-dd HH:mm&quot;</span>, <span class="hljs-string">&quot;yyyy/MM/dd&quot;</span>,<br>            <span class="hljs-string">&quot;yyyy/MM/dd HH:mm:ss&quot;</span>, <span class="hljs-string">&quot;yyyy/MM/dd HH:mm&quot;</span><br>    &#125;;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * The constant IS_NUM_PATTERN.</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Pattern</span> <span class="hljs-variable">IS_NUM_PATTERN</span> <span class="hljs-operator">=</span> Pattern.compile(<span class="hljs-string">&quot;-?[0-9]+(\\.[0-9]+)?&quot;</span>);<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * The constant MESSY_CODE_PATTERN.</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Pattern</span> <span class="hljs-variable">MESSY_CODE_PATTERN</span> <span class="hljs-operator">=</span> Pattern.compile(<span class="hljs-string">&quot;\\s*|\t*|\r*|\n*&quot;</span>);<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 解析字符串是否是日期</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> string the string</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the date</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Date <span class="hljs-title function_">parseDate</span><span class="hljs-params">(String string)</span> &#123;<br>        <span class="hljs-keyword">if</span> (string == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> DateUtils.parseDate(string, IS_DATE_PATTERNS);<br>        &#125; <span class="hljs-keyword">catch</span> (ParseException e) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 解析字符串是否是数字</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> str the str</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the boolean</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isNumeric</span><span class="hljs-params">(String str)</span> &#123;<br>        <span class="hljs-keyword">return</span> IS_NUM_PATTERN.matcher(str).matches();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取指定长度随机数</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> len the len</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the random</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">getRandom</span><span class="hljs-params">(<span class="hljs-type">int</span> len)</span> &#123;<br>        <span class="hljs-type">Random</span> <span class="hljs-variable">r</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Random</span>();<br>        <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">rs</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();<br>        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i &lt; len; i++) &#123;<br>            rs.append(r.nextInt(<span class="hljs-number">10</span>));<br>        &#125;<br>        <span class="hljs-keyword">return</span> rs.toString();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 获取指定长度字符</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> len       the len</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> character the character</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the characters</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">getCharacters</span><span class="hljs-params">(<span class="hljs-type">int</span> len, String character)</span> &#123;<br>        <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">rs</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();<br>        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i &lt; len; i++) &#123;<br>            rs.append(character);<br>        &#125;<br>        <span class="hljs-keyword">return</span> rs.toString();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 返回左移n位字符串方法</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> str      the str</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> position the position</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the string</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">moveToLeft</span><span class="hljs-params">(String str, <span class="hljs-type">int</span> position)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">str1</span> <span class="hljs-operator">=</span> str.substring(position);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">str2</span> <span class="hljs-operator">=</span> str.substring(<span class="hljs-number">0</span>, position);<br>        <span class="hljs-keyword">return</span> str1 + str2;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 返回右移n位字符串方法</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> str      the str</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> position the position</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the string</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title function_">moveToRight</span><span class="hljs-params">(String str, <span class="hljs-type">int</span> position)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">str1</span> <span class="hljs-operator">=</span> str.substring(str.length() - position);<br>        <span class="hljs-type">String</span> <span class="hljs-variable">str2</span> <span class="hljs-operator">=</span> str.substring(<span class="hljs-number">0</span>, str.length() - position);<br>        <span class="hljs-keyword">return</span> str1 + str2;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 检查字符串是否乱码</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> strName the str name</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> the boolean</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isMessyCode</span><span class="hljs-params">(String strName)</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Matcher</span> <span class="hljs-variable">m</span> <span class="hljs-operator">=</span> MESSY_CODE_PATTERN.matcher(strName);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">after</span> <span class="hljs-operator">=</span> m.replaceAll(<span class="hljs-string">&quot;&quot;</span>);<br>            <span class="hljs-type">String</span> <span class="hljs-variable">temp</span> <span class="hljs-operator">=</span> after.replaceAll(<span class="hljs-string">&quot;\\p&#123;P&#125;&quot;</span>, <span class="hljs-string">&quot;&quot;</span>);<br>            <span class="hljs-type">char</span>[] ch = temp.trim().toCharArray();<br><br>            <span class="hljs-keyword">for</span> (<span class="hljs-type">char</span> c : ch) &#123;<br>                <span class="hljs-keyword">if</span> (!Character.isLetterOrDigit(c)) &#123;<br>                    <span class="hljs-type">String</span> <span class="hljs-variable">str</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span> + c;<br>                    <span class="hljs-keyword">if</span> (!str.matches(<span class="hljs-string">&quot;[\u4e00-\u9fa5]+&quot;</span>)) &#123;<br>                        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>                    &#125;<br>                &#125;<br>            &#125;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 原始数据里匹配关键字替换成别的字符串</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>  String <span class="hljs-title function_">keywordReplacement</span><span class="hljs-params">(String rawData, String keyword, String replacementString)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">stringBuilder</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>(rawData);<br><br>        <span class="hljs-type">Matcher</span> <span class="hljs-variable">m</span> <span class="hljs-operator">=</span> Pattern.compile(keyword).matcher(stringBuilder);<br>        <span class="hljs-type">StringBuffer</span> <span class="hljs-variable">appendReplacement</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuffer</span>();<br>        <span class="hljs-keyword">while</span> (m.find()) &#123;<br>            m.appendReplacement(appendReplacement, replacementString);<br>        &#125;<br>        <span class="hljs-keyword">if</span> (StringUtils.isEmpty(appendReplacement)) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Exception</span>(<span class="hljs-string">&quot;原始数据里没有匹配到关键字&quot;</span>);<br>        &#125;<br>        m.appendTail(appendReplacement);<br><br>        <span class="hljs-keyword">return</span> appendReplacement.toString();<br>    &#125;<br>&#125;<br><br><br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">整理记录常用 Java 业务代码，以此备忘，持续更新中...</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Java" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Java/"/>
    
    
    <category term="Java" scheme="http://www.loquy.cn/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>使用 WinSW 将任何程序设为 Windows 服务</title>
    <link href="http://www.loquy.cn/posts/10bdb19a.html"/>
    <id>http://www.loquy.cn/posts/10bdb19a.html</id>
    <published>2022-06-08T02:13:03.000Z</published>
    <updated>2022-06-09T00:40:12.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h1><p>最新版本和预发布的 WinSW 二进制文件可在 <a href="https://github.com/winsw/winsw">GitHub Releases</a> 上获得。</p><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><h2 id="将-WinSW-用作捆绑工具"><a href="#将-WinSW-用作捆绑工具" class="headerlink" title="将 WinSW 用作捆绑工具"></a>将 WinSW 用作捆绑工具</h2><ul><li>从发行版中获取 <strong>WinSW.exe</strong> 或 <strong>WinSW.zip</strong>，然后根据您的喜好重命名.exe（例如 myapp.exe）。</li><li>编写 <strong>myapp.xml</strong> 。</li><li>将这两个文件并排放置，因为这就是 WinSW 发现其相关配置的方式。</li><li>运行 <a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#install-command">myapp.exe install</a> 以安装服务。</li><li>运行 <a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#status-command">myapp.exe start</a> 以启动服务。</li></ul><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>您编写定义服务的配置文件。<br>下面的示例是 Jenkins 项目中使用的原始示例：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">service</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>jenkins<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>Jenkins<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>This service runs Jenkins continuous integration system.<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">env</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;JENKINS_HOME&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;%BASE%&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">executable</span>&gt;</span>java<span class="hljs-tag">&lt;/<span class="hljs-name">executable</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">arguments</span>&gt;</span>-Xrs -Xmx256m -jar &quot;%BASE%\jenkins.war&quot; --httpPort=8080<span class="hljs-tag">&lt;/<span class="hljs-name">arguments</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">log</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">&quot;roll&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">log</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">service</span>&gt;</span><br></code></pre></td></tr></table></figure><p>配置文件的完整规范可在 <a href="https://github.com/winsw/winsw/blob/v3/docs/xml-config-file.md">此处</a> 获得。<br><a href="https://github.com/winsw/winsw/tree/v3/samples">您可以在此处</a> 找到更多示例。</p><h1 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h1><p>WinSW 由 <a href="https://github.com/winsw/winsw/blob/v3/docs/xml-config-file.md"> XML 配置文件</a> 管理。</p><p>您重命名的 <strong>WinSW.exe</strong> 二进制文件还接受以下命令：   </p><table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#install-command">install</a></td><td>安装服务。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#uninstall-command">uninstall</a></td><td>卸载服务。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#start-command">start</a></td><td>启动服务。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#stop-command">stop</a></td><td>停止服务。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#restart-command">restart</a></td><td>停止然后启动服务。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#status-command">status</a></td><td>检查服务的状态。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#refresh-command">refresh</a></td><td>无需重新安装即可刷新服务属性。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#customize-command">customize</a></td><td>自定义包装器可执行文件。</td></tr></tbody></table><p>实验命令：</p><table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#dev-ps-command">dev-ps</a></td><td>绘制与服务关联的进程树。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#dev-kill-command">dev-kill</a></td><td>如果服务停止响应，则终止服务。</td></tr><tr><td><a href="https://github.com/winsw/winsw/blob/v3/docs/cli-commands.md#dev-list-command">dev-list</a></td><td>列出由当前可执行文件管理的服务。</td></tr></tbody></table><p>大多数命令需要管理员权限才能执行。WinSW 将在非提升会话中提示输入 UAC。</p><h1 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h1><h2 id="Nacos"><a href="#Nacos" class="headerlink" title="Nacos"></a>Nacos</h2><h3 id="下载-1"><a href="#下载-1" class="headerlink" title="下载"></a>下载</h3><p>最新版本的 Nacos 文件可在 <a href="https://github.com/alibaba/nacos/releases">GitHub Releases</a> 上获得。</p><h3 id="配置-1"><a href="#配置-1" class="headerlink" title="配置"></a>配置</h3><p>编写 <strong>nacos-service.xml</strong> 配置执行 <strong>startup.cmd</strong>。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">service</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>nacos service<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>Nacos Service<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>Nacos-service<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logpath</span>&gt;</span>H:\environment\nacos\bin\logs\<span class="hljs-tag">&lt;/<span class="hljs-name">logpath</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">logmode</span>&gt;</span>roll<span class="hljs-tag">&lt;/<span class="hljs-name">logmode</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">executable</span>&gt;</span>H:\environment\nacos\bin\startup.cmd<span class="hljs-tag">&lt;/<span class="hljs-name">executable</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">stopexecutable</span>&gt;</span>H:\environment\nacos\bin\shutdown.cmd<span class="hljs-tag">&lt;/<span class="hljs-name">stopexecutable</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">service</span>&gt;</span><br></code></pre></td></tr></table></figure><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><ul><li>将 <strong>WinSW.exe</strong> 重命名为 <strong>nacos-service.exe</strong> 和 <strong>nacos-service.xml</strong> 放到同一个目录。</li><li>在 <strong>CMD</strong> 中运行 <strong>nacos-service.exe install</strong>。</li></ul><h2 id="Redis"><a href="#Redis" class="headerlink" title="Redis"></a>Redis</h2><h3 id="下载-2"><a href="#下载-2" class="headerlink" title="下载"></a>下载</h3><p>最新版本的 Redis 文件可在 <a href="https://github.com/redis/redis/releases">GitHub Releases</a> 上获得。</p><h3 id="配置-2"><a href="#配置-2" class="headerlink" title="配置"></a>配置</h3><p>编写 <strong>Redis.xml</strong> 配置执行 <strong>redis-server.exe</strong>。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">service</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务ID--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>Redis<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务名--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>Redis<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务描述--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>Redis<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br> <span class="hljs-comment">&lt;!--运行方式--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">executable</span>&gt;</span><br>     H:\environment\Redis-x64-5.0.14\redis-server.exe<br> <span class="hljs-tag">&lt;/<span class="hljs-name">executable</span>&gt;</span><br> <span class="hljs-comment">&lt;!-- 日志配置 --&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">logpath</span>&gt;</span>H:\environment\Redis-x64-5.0.14\log<span class="hljs-tag">&lt;/<span class="hljs-name">logpath</span>&gt;</span><br> <span class="hljs-comment">&lt;!--日志重置 (rotate循环追加)--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">logmode</span>&gt;</span>reset<span class="hljs-tag">&lt;/<span class="hljs-name">logmode</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">service</span>&gt;</span><br></code></pre></td></tr></table></figure><h3 id="安装-1"><a href="#安装-1" class="headerlink" title="安装"></a>安装</h3><ul><li>将 <strong>WinSW.exe</strong> 重命名为 <strong>Redis.exe</strong> 和 <strong>Redis.xml</strong> 放到同一个目录。</li><li>在 <strong>CMD</strong> 中运行 <strong>Redis.exe install</strong>。</li></ul><h2 id="VirtualBox"><a href="#VirtualBox" class="headerlink" title="VirtualBox"></a>VirtualBox</h2><h3 id="下载-3"><a href="#下载-3" class="headerlink" title="下载"></a>下载</h3><p>最新版本的 VirtualBox 文件可在 <a href="https://www.virtualbox.org/wiki/Downloads">官网</a> 上获得。</p><h3 id="配置-3"><a href="#配置-3" class="headerlink" title="配置"></a>配置</h3><p>编写 <strong>startup.bat</strong> 执行脚本, 命令为启动两个虚拟机。     </p><figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bat">@<span class="hljs-built_in">ECHO</span> OFF<br><span class="hljs-built_in">cd</span> C:\Program Files\Oracle\VirtualBox\<br><span class="hljs-built_in">start</span> VBoxManage.exe startvm  CentOS-Stream-<span class="hljs-number">9</span> --<span class="hljs-built_in">type</span> headless<br><span class="hljs-built_in">cd</span> C:\Program Files\Oracle\VirtualBox\<br><span class="hljs-built_in">start</span> VBoxManage.exe startvm startvm cs --<span class="hljs-built_in">type</span> headless<br><span class="hljs-keyword">EXIT</span><br></code></pre></td></tr></table></figure><p>编写 <strong>VirtualBox.xml</strong> 配置执行 <strong>startup.bat</strong> 文件。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">service</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务ID--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>VirtualBox<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务名--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>VirtualBox<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务描述--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>VirtualBox<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br> <span class="hljs-comment">&lt;!--运行方式--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">executable</span>&gt;</span><br>     H:\environment\VirtualBox\startup.bat<br> <span class="hljs-tag">&lt;/<span class="hljs-name">executable</span>&gt;</span><br> <span class="hljs-comment">&lt;!-- 日志配置 --&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">logpath</span>&gt;</span>H:\environment\VirtualBox\log<span class="hljs-tag">&lt;/<span class="hljs-name">logpath</span>&gt;</span><br> <span class="hljs-comment">&lt;!--日志重置 (rotate循环追加)--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">logmode</span>&gt;</span>reset<span class="hljs-tag">&lt;/<span class="hljs-name">logmode</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">service</span>&gt;</span><br></code></pre></td></tr></table></figure><h3 id="安装-2"><a href="#安装-2" class="headerlink" title="安装"></a>安装</h3><ul><li>将 <strong>WinSW.exe</strong> 重命名为 <strong>VirtualBox.exe</strong> 和 <strong>VirtualBox.xml</strong> 放到同一个目录。</li><li>在 <strong>CMD</strong> 中运行 <strong>VirtualBox.exe install</strong>。</li></ul><h2 id="Sentinel"><a href="#Sentinel" class="headerlink" title="Sentinel"></a>Sentinel</h2><h3 id="下载-4"><a href="#下载-4" class="headerlink" title="下载"></a>下载</h3><p>最新版本的 Sentinel 文件可在 <a href="https://github.com/alibaba/Sentinel/releases">GitHub Releases</a> 上获得。</p><h3 id="配置-4"><a href="#配置-4" class="headerlink" title="配置"></a>配置</h3><p>编写 <strong>startup.bat</strong> 执行脚本, 命令为启动 jar 包。</p><figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bat">@<span class="hljs-built_in">ECHO</span> OFF<br>java -Dserver.port=<span class="hljs-number">8718</span> -Dcsp.sentinel.dashboard.server=localhost:<span class="hljs-number">8718</span> -Dproject.name=sentinel-dashboard -jar &quot;H:\environment\sentinel\sentinel-dashboard.jar&quot;<br><span class="hljs-keyword">EXIT</span><br></code></pre></td></tr></table></figure><p>编写 <strong>sentinel-dashboard.xml</strong> 配置执行 <strong>startup.bat</strong> 文件。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">service</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务ID--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>sentinel-dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务名--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>sentinel-dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span><br> <span class="hljs-comment">&lt;!--服务描述--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>sentinel-dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span><br> <span class="hljs-comment">&lt;!--运行方式--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">executable</span>&gt;</span><br>     H:\environment\sentinel\startup.bat<br> <span class="hljs-tag">&lt;/<span class="hljs-name">executable</span>&gt;</span><br> <span class="hljs-comment">&lt;!-- 日志配置 --&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">logpath</span>&gt;</span>H:\environment\sentinel\log<span class="hljs-tag">&lt;/<span class="hljs-name">logpath</span>&gt;</span><br> <span class="hljs-comment">&lt;!--日志重置 (rotate循环追加)--&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">logmode</span>&gt;</span>reset<span class="hljs-tag">&lt;/<span class="hljs-name">logmode</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">service</span>&gt;</span><br></code></pre></td></tr></table></figure><h3 id="安装-3"><a href="#安装-3" class="headerlink" title="安装"></a>安装</h3><ul><li>将 <strong>WinSW.exe</strong> 重命名为 <strong>sentinel-dashboard.exe</strong> 和 <strong>sentinel-dashboard.xml</strong> 放到同一个目录。</li><li>在 <strong>CMD</strong> 中运行 <strong>sentinel-dashboard.exe install</strong>。</li></ul><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://github.com/winsw/winsw">WinSW</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;下载&quot;&gt;&lt;a href=&quot;#下载&quot; class=&quot;headerlink&quot; title=&quot;下载&quot;&gt;&lt;/a&gt;下载&lt;/h1&gt;&lt;p&gt;最新版本和预发布的 WinSW 二进制文件可在 &lt;a href=&quot;https://github.com/winsw/winsw&quot;&gt;GitHu</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Windows" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Windows/"/>
    
    
    <category term="Windows" scheme="http://www.loquy.cn/tags/Windows/"/>
    
    <category term="WinSW" scheme="http://www.loquy.cn/tags/WinSW/"/>
    
  </entry>
  
  <entry>
    <title>GitLab 安装和使用</title>
    <link href="http://www.loquy.cn/posts/e2e5d3b3.html"/>
    <id>http://www.loquy.cn/posts/e2e5d3b3.html</id>
    <published>2021-07-01T01:27:14.000Z</published>
    <updated>2021-07-01T06:12:10.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p><a href="https://docs.gitlab.com/ee/install/requirements.html">GitLab 官方安装要求</a></p><pre><code class="hljs">系统：可自由选择，我虚拟机上的是 CentOS Stream release 8CPU：4 核是建议的最低核数，最多支持 500 个用户内存：4GB RAM 是所需的最小内存大小，最多支持 500 个用户硬盘：必要的硬盘空间在很大程度上取决于您要存储在 GitLab 中的存储库的大小，但根据经验，您应该拥有至少与所有存储库组合占用的空间一样多的可用空间</code></pre><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><ul><li>安装和配置必要的依赖项</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo dnf install -y curl policycoreutils openssh-server perl<br>sudo systemctl <span class="hljs-built_in">enable</span> sshd<br>sudo systemctl start sshd<br><br><span class="hljs-comment"># Check if opening the firewall is needed with: sudo systemctl status firewalld</span><br>sudo firewall-cmd --permanent --add-service=http<br>sudo firewall-cmd --permanent --add-service=https<br>sudo systemctl reload firewalld<br></code></pre></td></tr></table></figure><ul><li>下载 gitlab-ce 社区版的 <a href="https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el8/">rpm</a> 包</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">rpm -ivh gitlab-ce-12.10.0-ce.0.el8.x86_64.rpm<br></code></pre></td></tr></table></figure><ul><li><p>修改 gitlab 默认配置</p><p>  编辑 &#x2F;etc&#x2F;gitlab&#x2F;gitlab.rb 搜索 external_url </p><p>  把后面的地址修改为你自己的域名或者 IP，是单引号，而且前面的 http 不要改</p><p>  默认填写 http:&#x2F;&#x2F; 加上本机 IP 即可，如需自定义域名需加入到 &#x2F;etc&#x2F;hosts 中</p></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">vim /etc/gitlab/gitlab.rb<br></code></pre></td></tr></table></figure><ul><li>重新加载配置后重启 gitlab</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">gitlab-ctl reconfigure<br>gitlab-ctl restart<br></code></pre></td></tr></table></figure><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><h2 id="初始化账户与创建仓库"><a href="#初始化账户与创建仓库" class="headerlink" title="初始化账户与创建仓库"></a>初始化账户与创建仓库</h2><pre><code class="hljs">打开浏览器输入配置的 external_url进行初始化账户设定密码，这个密码为 root 管理员账户的密码设置完密码之后会自动跳转到登录页面可以使用 root 登录，也可以在登录界面创建一个账户登录，登录后创建仓库</code></pre><h2 id="安装-Git-后配置-SSH-Key"><a href="#安装-Git-后配置-SSH-Key" class="headerlink" title="安装 Git 后配置 SSH-Key"></a>安装 Git 后配置 SSH-Key</h2><ul><li>安装 <a href="https://git-scm.com/book/zh/v2">Git</a> 安装后设置你的用户名和邮件地址</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">git config --global user.name <span class="hljs-string">&quot;John Doe&quot;</span><br>git config --global user.email johndoe@example.com<br></code></pre></td></tr></table></figure><ul><li>在 Git Bash 上生成 SSH-Key</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">ssh-keygen -t rsa -C <span class="hljs-string">&#x27;email&#x27;</span> -f ~/.ssh/local_gitlab_rsa<br></code></pre></td></tr></table></figure><ul><li>在 ~&#x2F;.ssh 目录下新建一个 config 文件</li></ul><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs awk"><span class="hljs-comment">#gitlab</span><br>HostName gitlab 的主机 IP<br>IdentityFile  ~<span class="hljs-regexp">/.ssh/</span>local_gitlab_rsa<br></code></pre></td></tr></table></figure><ul><li><p>添加秘钥</p><p>  点击右上角头像，Settings -&gt; SSH </p><p>  把刚刚生成的 ~&#x2F;.ssh&#x2F;local_gitlab_rsa.pua 文件的内容粘贴上</p><p>  添加一个 Title，然后 Add Key</p></li><li><p>Git 工作流</p></li></ul><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs crmsh">git <span class="hljs-keyword">clone</span><br><span class="hljs-title">git</span> add<br>git commit<br>git push<br>git pull<br>...<br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://about.gitlab.com/install/#centos-8">GitLab 官方安装文档</a></li><li><a href="https://docs.gitlab.com/ee/install/requirements.html">GitLab 官方安装要求</a></li><li><a href="https://git-scm.com/book/zh/v2">Git Book</a></li><li><a href="https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el8/">清华大学镜像</a></li><li><a href="https://cloud.tencent.com/developer/article/1728804">GitLab 安装与基础使用</a></li><li><a href="https://gitee.com/help/articles/4229#article-header0">Git 配置多个 SSH-Key</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;环境&quot;&gt;&lt;a href=&quot;#环境&quot; class=&quot;headerlink&quot; title=&quot;环境&quot;&gt;&lt;/a&gt;环境&lt;/h1&gt;&lt;p&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/install/requirements.html&quot;&gt;GitLab </summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Git" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Git/"/>
    
    
    <category term="Git" scheme="http://www.loquy.cn/tags/Git/"/>
    
    <category term="GitLab" scheme="http://www.loquy.cn/tags/GitLab/"/>
    
  </entry>
  
  <entry>
    <title>在 PHP 中使用单元测试</title>
    <link href="http://www.loquy.cn/posts/ef77815d.html"/>
    <id>http://www.loquy.cn/posts/ef77815d.html</id>
    <published>2021-05-30T00:17:04.000Z</published>
    <updated>2021-05-30T00:17:04.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="相关概念"><a href="#相关概念" class="headerlink" title="相关概念"></a>相关概念</h1><ul><li><code>单元测试</code><br>单元测试是针对程序的最小单元进行测试，方法、类等都可以是一个单元，根据实际情况判定，一般指的是方法。</li><li><code>断言</code><br>在程序设计中，断言（assertion）是一种放在程序中的一阶逻辑（如一个结果为真或是假的逻辑判断式），目的是为了标示与验证程序开发者预期的结果－当程序运行到断言的位置时，对应的断言应该为真。若断言不为真时，程序会中止运行，并给出错误消息。</li><li><code>PHPUnit</code><br>是一个轻量级的 PHP 测试框架</li></ul><h1 id="PHPUnit-的安装和配置"><a href="#PHPUnit-的安装和配置" class="headerlink" title="PHPUnit 的安装和配置"></a>PHPUnit 的安装和配置</h1><p>目前支持的版本是PHPUnit 9</p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a><a href="https://phpunit.de/getting-started/phpunit-9.html">安装</a></h2><h3 id="PHP-档案包（PHAR）"><a href="#PHP-档案包（PHAR）" class="headerlink" title="PHP 档案包（PHAR）"></a>PHP 档案包（PHAR）</h3><pre><code class="hljs">➜ wget -O phpunit https://phar.phpunit.de/phpunit-9.phar➜ chmod +x phpunit➜ ./phpunit --versionPHPUnit 9.0.0 by Sebastian Bergmann and contributors.</code></pre><h3 id="Composer"><a href="#Composer" class="headerlink" title="Composer"></a>Composer</h3><pre><code class="hljs">➜ composer require --dev phpunit/phpunit ^9➜ ./vendor/bin/phpunit --versionPHPUnit 9.0.0 by Sebastian Bergmann and contributors.</code></pre><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><h3 id="XML-配置文件"><a href="#XML-配置文件" class="headerlink" title="XML 配置文件"></a><a href="https://phpunit.readthedocs.io/zh_CN/latest/configuration.html">XML 配置文件</a></h3><p>用于编排测试套件，示例如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">phpunit</span> <span class="hljs-attr">bootstrap</span>=<span class="hljs-string">&quot;./bootstrap.php&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">colors</span>=<span class="hljs-string">&quot;true&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">verbose</span>=<span class="hljs-string">&quot;true&quot;</span></span><br><span class="hljs-tag">&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">php</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">ini</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;error_reporting&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;-1&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">php</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">testsuites</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">testsuite</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;test&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">directory</span>&gt;</span>./Tests/<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">testsuite</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">testsuites</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">phpunit</span>&gt;</span><br></code></pre></td></tr></table></figure><h3 id="Bootstrap-启动文件"><a href="#Bootstrap-启动文件" class="headerlink" title="Bootstrap 启动文件"></a>Bootstrap 启动文件</h3><p>在启动 PHPUnit 时会加载的文件，用于自动加载依赖等，示例如下：</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-variable">$classNameMap</span> = [<br>    <span class="hljs-string">&#x27;single&#x27;</span> =&gt; <span class="hljs-keyword">__DIR__</span> . DIRECTORY_SEPARATOR . <span class="hljs-string">&#x27;single&#x27;</span>,<br>];<br><br><span class="hljs-title function_ invoke__">spl_autoload_register</span>(function(<span class="hljs-variable">$className</span>) <span class="hljs-keyword">use</span> ($<span class="hljs-title">classNameMap</span>) &#123;<br>    $<span class="hljs-title">position</span> = <span class="hljs-title">strpos</span>($<span class="hljs-title">className</span>, &#x27;\\&#x27;);<br>    <span class="hljs-keyword">if</span> (<span class="hljs-variable">$position</span>) &#123;<br>        <span class="hljs-variable">$namespace</span> = <span class="hljs-title function_ invoke__">substr</span>(<span class="hljs-variable">$className</span>, <span class="hljs-number">0</span>, <span class="hljs-variable">$position</span>);<br>        <span class="hljs-variable">$directory</span> = <span class="hljs-variable">$classNameMap</span>[<span class="hljs-variable">$namespace</span>] ?? <span class="hljs-string">&#x27;&#x27;</span>;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-variable">$directory</span>) &#123;<br>            <span class="hljs-variable">$classFile</span> = <span class="hljs-variable">$directory</span> . <span class="hljs-title function_ invoke__">substr</span>(<span class="hljs-variable">$className</span>, <span class="hljs-variable">$position</span>) . <span class="hljs-string">&#x27;.php&#x27;</span>;<br>            <span class="hljs-title function_ invoke__">is_file</span>(<span class="hljs-variable">$classFile</span>) &amp;&amp; <span class="hljs-keyword">require</span> <span class="hljs-variable">$classFile</span>;<br>        &#125;<br>    &#125;<br>&#125;);<br></code></pre></td></tr></table></figure><h3 id="在-PhpStorm-里配置使用"><a href="#在-PhpStorm-里配置使用" class="headerlink" title="在 PhpStorm 里配置使用"></a>在 PhpStorm 里配置使用</h3><ul><li>文件 -&gt; 设置 -&gt; PHP，设置 cli 解释器。</li><li>文件 -&gt; 设置 -&gt; PHP -&gt; 测试框架，设置 phpunit.phar 路径或 composer 下的 phpunit 路径， 设置 xml 配置文件。</li><li>使用 IDE 自动帮我们执行 PHPUnit 的命令，便不用手动操作了，测试时只需点击文件里的执行按钮即可。</li></ul><h1 id="编写-PHPUnit-测试"><a href="#编写-PHPUnit-测试" class="headerlink" title="编写 PHPUnit 测试"></a>编写 PHPUnit 测试</h1><h2 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h2><ul><li>针对类 Class 的测试写在类 ClassTest 中。</li><li>ClassTest（通常）继承自 PHPUnit\Framework\TestCase。</li><li>测试都是命名为 test* 的公用方法。</li><li>也可以在方法的文档注释块（docblock）中使用 @test 标注将其标记为测试方法。在测试方法内，类似于 assertSame()（<a href="https://phpunit.readthedocs.io/zh_CN/latest/assertions.html">参见断言</a>）这样的断言方法用来对实际值与预期值的匹配做出断言。</li></ul><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><ul><li>类<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">single</span>;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">test</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-variable">$attr</span>;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hello</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span></span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;hello&#x27;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></li><li>测试类<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-keyword">use</span> <span class="hljs-title">PHPUnit</span>\<span class="hljs-title">Framework</span>\<span class="hljs-title">TestCase</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-title">single</span>\<span class="hljs-title">test</span>;<br><br><span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Assert</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testIsTheContrastEqual</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">assertEquals</span>(<span class="hljs-string">&#x27;hello&#x27;</span>, (<span class="hljs-keyword">new</span> test)-&gt;<span class="hljs-title function_ invoke__">hello</span>());<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testIsThereAnyAttribute</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">assertClassHasAttribute</span>(<span class="hljs-string">&#x27;attr&#x27;</span>, test::<span class="hljs-variable language_">class</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></li><li>执行结果<br><img src="https://www.loquy.cn/images/PHPUnit.jpg" alt="execution"></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;相关概念&quot;&gt;&lt;a href=&quot;#相关概念&quot; class=&quot;headerlink&quot; title=&quot;相关概念&quot;&gt;&lt;/a&gt;相关概念&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;单元测试&lt;/code&gt;&lt;br&gt;单元测试是针对程序的最小单元进行测试，方法、类等都可以是一个单元，根据</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="单元测试" scheme="http://www.loquy.cn/tags/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>在 PHP 中使用多进程</title>
    <link href="http://www.loquy.cn/posts/68d862bb.html"/>
    <id>http://www.loquy.cn/posts/68d862bb.html</id>
    <published>2021-04-04T15:38:28.000Z</published>
    <updated>2021-04-06T14:27:28.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="多道程序设计以及顺序和并发执行"><a href="#多道程序设计以及顺序和并发执行" class="headerlink" title="多道程序设计以及顺序和并发执行"></a>多道程序设计以及顺序和并发执行</h2><ul><li>所谓多道程序设计，就是允许多个程序同时进入内存并运行。多道程序设计是操作系统所采用的最基本、最重要的技术，其根本目的是提高整个系统的效率。</li><li>程序是一个在时间上按严格次序前后相继的操作序列，具有独立功能的程序独占处理器直到得到最终结果的过程称为程序的顺序执行。所谓程序的并发执行，是指两个或两个以上程序在计算机系统中，同时处于开始执行且尚未结束的状态。</li></ul><h3 id="进程和线程"><a href="#进程和线程" class="headerlink" title="进程和线程"></a>进程和线程</h3><ul><li>进程是具有一定独立功能的程序在某个数据集合上的一次运行活动，是系统进行资源分配和调度的一个基本单位。</li><li>线程是进程中的一个实体，是处理器调度和分派的基本单位。线程自己基本上不拥有系统资源，只拥有少量在运行中必不可少的资源（如程序计数器、一组寄存器和栈等），但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程；同一个进程中的多个线程之间可以并发执行。由于线程之间的制约，至使线程在运行中也呈现出间断性。相应的，线程也同样拥有就绪、等待和运行三种基本状态。有的系统中线程还有终止状态等。</li></ul><h2 id="相关函数"><a href="#相关函数" class="headerlink" title="相关函数"></a>相关函数</h2><h3 id="程序执行函数"><a href="#程序执行函数" class="headerlink" title="程序执行函数"></a>程序执行函数</h3><ul><li><a href="https://www.php.net/manual/zh/function.escapeshellarg.php">escapeshellarg</a> — 把字符串转码为可以在 shell 命令里使用的参数</li><li><a href="https://www.php.net/manual/zh/function.escapeshellcmd.php">escapeshellcmd</a> — shell 元字符转义</li><li><a href="https://www.php.net/manual/zh/function.exec.php">exec</a> — 执行一个外部程序</li><li><a href="https://www.php.net/manual/zh/function.passthru.php">passthru</a> — 执行外部程序并且显示原始输出</li><li><a href="https://www.php.net/manual/zh/function.proc-close.php">proc_close</a> — 关闭由 proc_open 打开的进程并且返回进程退出码</li><li><a href="https://www.php.net/manual/zh/function.proc-get-status.php">proc_get_status</a> — 获取由 proc_open 函数打开的进程的信息</li><li><a href="https://www.php.net/manual/zh/function.proc-nice.php">proc_nice</a> — 修改当前进程的优先级</li><li><a href="https://www.php.net/manual/zh/function.proc-open.php">proc_open</a> — 执行一个命令，并且打开用来输入&#x2F;输出的文件指针。</li><li><a href="https://www.php.net/manual/zh/function.proc-terminate.php">proc_terminate</a> — 杀除由 proc_open 打开的进程</li><li><a href="https://www.php.net/manual/zh/function.shell-exec.php">shell_exec</a> — 通过 shell 环境执行命令，并且将完整的输出以字符串的方式返回。</li><li><a href="https://www.php.net/manual/zh/function.system.php">system</a> — 执行外部程序，并且显示输出</li></ul><h3 id="文件系统函数"><a href="#文件系统函数" class="headerlink" title="文件系统函数"></a>文件系统函数</h3><ul><li><a href="https://www.php.net/manual/zh/function.pclose.php">pclose</a> — 关闭进程文件指针</li><li><a href="https://www.php.net/manual/zh/function.popen.php">popen</a> — 打开进程文件指针</li></ul><h3 id="网络函数"><a href="#网络函数" class="headerlink" title="网络函数"></a>网络函数</h3><ul><li><a href="https://www.php.net/manual/zh/function.fsockopen.php">fsockopen</a> — 打开一个网络连接或者一个Unix套接字连接</li></ul><h2 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h2><h3 id="开启多个进程，检查代理节点-ip-port-是否可以连接"><a href="#开启多个进程，检查代理节点-ip-port-是否可以连接" class="headerlink" title="开启多个进程，检查代理节点 ip:port 是否可以连接"></a>开启多个进程，检查代理节点 ip:port 是否可以连接</h3><p>deadoralive.php</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-variable">$json</span> = <span class="hljs-title function_ invoke__">file_get_contents</span>(<span class="hljs-string">&#x27;./node.json&#x27;</span>);<br><span class="hljs-variable">$array</span> = <span class="hljs-title function_ invoke__">json_decode</span>(<span class="hljs-variable">$json</span>, <span class="hljs-literal">true</span>);<br><span class="hljs-variable">$array</span> = <span class="hljs-title function_ invoke__">array_chunk</span>(<span class="hljs-variable">$array</span>, <span class="hljs-variable">$argv</span>[<span class="hljs-number">1</span>]);<br><span class="hljs-variable">$connection</span> = [];<br><span class="hljs-variable">$success</span> = <span class="hljs-number">0</span>;<br><span class="hljs-variable">$unit</span> = <span class="hljs-variable">$argv</span>[<span class="hljs-number">2</span>];<br><span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$array</span>[<span class="hljs-variable">$unit</span>] <span class="hljs-keyword">as</span> <span class="hljs-variable">$value</span>) &#123;<br>    <span class="hljs-variable">$ip</span> = <span class="hljs-variable">$value</span>[<span class="hljs-string">&#x27;server&#x27;</span>];<br>    <span class="hljs-variable">$port</span> = <span class="hljs-variable">$value</span>[<span class="hljs-string">&#x27;server_port&#x27;</span>];<br>    <span class="hljs-variable">$deadoralive</span> = @<span class="hljs-title function_ invoke__">fsockopen</span>(<span class="hljs-variable">$ip</span>, <span class="hljs-variable">$port</span>, <span class="hljs-variable">$errno</span>, <span class="hljs-variable">$errstr</span>, <span class="hljs-number">1</span>);<br><br>    <span class="hljs-keyword">if</span> (!<span class="hljs-variable">$deadoralive</span>) &#123;<br>        <span class="hljs-keyword">echo</span> <span class="hljs-title function_ invoke__">getmypid</span>() . <span class="hljs-string">&quot; | The IP address, <span class="hljs-subst">$ip</span>, is dead&quot;</span> . <span class="hljs-string">&quot;\n&quot;</span>;<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-variable">$success</span>++;<br>        <span class="hljs-variable">$connection</span>[] = <span class="hljs-variable">$value</span>;<br>        <span class="hljs-keyword">echo</span> <span class="hljs-title function_ invoke__">getmypid</span>() . <span class="hljs-string">&quot; | The IP address, <span class="hljs-subst">$ip</span>, is alive&quot;</span>. <span class="hljs-string">&quot;\n&quot;</span>;<br>    &#125;<br>&#125;<br><span class="hljs-variable">$total</span> = <span class="hljs-title function_ invoke__">count</span>(<span class="hljs-variable">$array</span>[<span class="hljs-variable">$unit</span>]);<br><span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;\033[31m unit: <span class="hljs-subst">$unit</span> |total: <span class="hljs-subst">$total</span> |success: <span class="hljs-subst">$success</span> \033[0m \n&quot;</span>;<br><span class="hljs-variable">$connection</span> = <span class="hljs-title function_ invoke__">print_r</span>(<span class="hljs-variable">$connection</span>, <span class="hljs-literal">true</span>);<br><span class="hljs-title function_ invoke__">file_put_contents</span>(<span class="hljs-string">&#x27;./alivenode_&#x27;</span> . <span class="hljs-variable">$argv</span>[<span class="hljs-number">3</span>] . <span class="hljs-string">&#x27;.log&#x27;</span>, <span class="hljs-variable">$connection</span>, FILE_APPEND);<br></code></pre></td></tr></table></figure><p>process.php</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-variable">$time</span> = <span class="hljs-title function_ invoke__">time</span>();<br><span class="hljs-variable">$begin</span> = <span class="hljs-title function_ invoke__">round</span>(<span class="hljs-title function_ invoke__">microtime</span>(<span class="hljs-literal">true</span>), <span class="hljs-number">4</span>);<br><span class="hljs-variable">$json</span> = <span class="hljs-title function_ invoke__">file_get_contents</span>(<span class="hljs-string">&#x27;./node.json&#x27;</span>);<br><span class="hljs-variable">$array</span> = <span class="hljs-title function_ invoke__">json_decode</span>(<span class="hljs-variable">$json</span>, <span class="hljs-literal">true</span>);<br><span class="hljs-variable">$size</span> = <span class="hljs-number">5</span>;<br><span class="hljs-variable">$chunk</span> = <span class="hljs-title function_ invoke__">count</span>(<span class="hljs-variable">$array</span>) / <span class="hljs-variable">$size</span>;<br><span class="hljs-variable">$chunk</span> = <span class="hljs-title function_ invoke__">ceil</span>(<span class="hljs-variable">$chunk</span>);<br><span class="hljs-comment">// 此处使用 popen 开启多进程，同理可以使用 proc_open、exec 等函数实现</span><br><span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span>=<span class="hljs-number">0</span>; <span class="hljs-variable">$i</span> &lt; <span class="hljs-variable">$chunk</span>; <span class="hljs-variable">$i</span>++) &#123;<br>    <span class="hljs-variable">$pipe</span>[<span class="hljs-variable">$i</span>] = <span class="hljs-title function_ invoke__">popen</span>(<span class="hljs-string">&#x27;php ./deadoralive.php &#x27;</span> . <span class="hljs-variable">$size</span> . <span class="hljs-string">&#x27; &#x27;</span>. <span class="hljs-variable">$i</span> . <span class="hljs-string">&#x27; &#x27;</span> . <span class="hljs-variable">$time</span>, <span class="hljs-string">&#x27;w&#x27;</span>);<br>&#125;<br><span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span>=<span class="hljs-number">0</span>; <span class="hljs-variable">$i</span> &lt; <span class="hljs-variable">$chunk</span>; <span class="hljs-variable">$i</span>++) &#123;<br>    <span class="hljs-variable">$r</span> = <span class="hljs-title function_ invoke__">pclose</span>(<span class="hljs-variable">$pipe</span>[<span class="hljs-variable">$i</span>]);<br>&#125;<br><span class="hljs-variable">$end</span> = <span class="hljs-title function_ invoke__">round</span>(<span class="hljs-title function_ invoke__">microtime</span>(<span class="hljs-literal">true</span>), <span class="hljs-number">4</span>);<br><span class="hljs-keyword">echo</span> <span class="hljs-variable">$end</span> - <span class="hljs-variable">$begin</span> . <span class="hljs-string">&quot;\n&quot;</span>;<br></code></pre></td></tr></table></figure><p>cli 模式下执行命令 php process.php ，效率还行 181 个节点 12 秒就跑完了<br><img src="https://www.loquy.cn/images/proxy_checker.jpg" alt="ouput"></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;ul&gt;
&lt;li&gt;所谓多道程序设计，就是允</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="PHP" scheme="http://www.loquy.cn/tags/PHP/"/>
    
  </entry>
  
  <entry>
    <title>Vim 常用命令和配置</title>
    <link href="http://www.loquy.cn/posts/3f5e4d56.html"/>
    <id>http://www.loquy.cn/posts/3f5e4d56.html</id>
    <published>2020-10-12T15:00:00.000Z</published>
    <updated>2020-10-13T02:50:00.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="模式"><a href="#模式" class="headerlink" title="模式"></a>模式</h1><p>在其他模式下使用 <code>Esc</code> 切换回普通模式，命令行模式下使用 <code>:命令</code> + <code>Enter</code> 执行命令。</p><table><thead><tr><th align="left">命令</th><th align="left">模式</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>默认</code></td><td align="left">普通模式</td><td align="left">控制光标移动，可对文本进行复制、粘贴等操作</td></tr><tr><td align="left"><code>i</code></td><td align="left">插入模式</td><td align="left">写入和编辑文本</td></tr><tr><td align="left"><code>:</code></td><td align="left">命令行模式</td><td align="left">保存或退出文本等，设置 Vim 的配置项</td></tr><tr><td align="left"><code>v</code></td><td align="left">可视模式</td><td align="left">配合方向键选取某一块文本区域，像使用鼠标一样</td></tr></tbody></table><h1 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h1><p>注意 <code>n</code> 为数字，<code>+</code> 表示组合使用，其他的字符对应键盘上的按键。</p><ol><li><p>普通模式：</p><p> 常用的光标移动命令。</p><table><thead><tr><th align="left">命令</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>n + h</code> 或 <code>n + ←</code></td><td align="left">光标左移 n 个位置</td></tr><tr><td align="left"><code>n + l</code> 或 <code>n + →</code></td><td align="left">光标右移 n 个位置</td></tr><tr><td align="left"><code>n + j</code> 或 <code>n + ↓</code></td><td align="left">光标下移 n 个位置</td></tr><tr><td align="left"><code>n + k</code> 或 <code>n + ↑</code></td><td align="left">光标上移 n 个位置</td></tr><tr><td align="left"><code>ctrl + f</code></td><td align="left">向下滚动一屏</td></tr><tr><td align="left"><code>ctrl + b</code></td><td align="left">向上滚动一屏</td></tr><tr><td align="left"><code>ctrl + d</code></td><td align="left">向下滚动半屏</td></tr><tr><td align="left"><code>ctrl + u</code></td><td align="left">向上滚动半屏</td></tr><tr><td align="left"><code>0</code></td><td align="left">跳到首行，可以理解为无穷大的h</td></tr><tr><td align="left"><code>^</code></td><td align="left">跳到行首开始的第一个非空白字符</td></tr><tr><td align="left"><code>$</code></td><td align="left">跳到行尾，可以理解为无穷大的l</td></tr><tr><td align="left"><code>gg</code> 或 <code>1 + G</code></td><td align="left">跳到首行，可以理解为无穷大的k</td></tr><tr><td align="left"><code>G</code></td><td align="left">跳到末行，可以理解为无穷大的j</td></tr><tr><td align="left"><code>w</code></td><td align="left">跳到下一个词首</td></tr><tr><td align="left"><code>b</code></td><td align="left">跳到上一个词首</td></tr><tr><td align="left"><code>e</code></td><td align="left">跳到下一个词尾</td></tr><tr><td align="left"><code>ge</code></td><td align="left">跳到上一个词尾</td></tr><tr><td align="left"><code>H</code></td><td align="left">移动到屏幕的最上方那一行的第一个字符</td></tr><tr><td align="left"><code>M</code></td><td align="left">移动到屏幕的最中央那一行的第一个字符</td></tr><tr><td align="left"><code>L</code></td><td align="left">移动到屏幕的最下方那一行的第一个字符</td></tr><tr><td align="left"><code>n + Enter</code></td><td align="left">光标向下移动 n 行</td></tr><tr><td align="left"><code>c</code></td><td align="left">删除当前光标后面的部分. 进入插入模式</td></tr><tr><td align="left"><code>cc</code></td><td align="left">将当前行替换为空行，进入插入模式</td></tr><tr><td align="left"><code>cw</code></td><td align="left">删除当前单词的光标右侧部分，进入插入模式</td></tr><tr><td align="left"><code>s</code></td><td align="left">删除当前字母，进入插入模式</td></tr><tr><td align="left"><code>r</code></td><td align="left">替换当前字母，输入一个字母后自动返回普通模式</td></tr><tr><td align="left"><code>a</code></td><td align="left">在光标右侧插入文本</td></tr><tr><td align="left"><code>A</code></td><td align="left">在行末插入文本</td></tr><tr><td align="left"><code>i</code></td><td align="left">在光标左侧插入文本</td></tr><tr><td align="left"><code>I</code></td><td align="left">在行首插入文本</td></tr><tr><td align="left"><code>o</code></td><td align="left">在光标下插入新行</td></tr><tr><td align="left"><code>O</code></td><td align="left">在光标上插入新行</td></tr><tr><td align="left"><code>n</code></td><td align="left">跳转下一个搜索词</td></tr><tr><td align="left"><code>N</code></td><td align="left">跳转上一个搜索词</td></tr></tbody></table><p> 常用的复制、黏贴、删除、撤销、查找等操作。</p><table><thead><tr><th align="left">命令</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>n + x</code></td><td align="left">剪切（删除）光标右边n个字符</td></tr><tr><td align="left"><code>n + X</code></td><td align="left">剪切（删除）光标左边n个字符</td></tr><tr><td align="left"><code>y</code></td><td align="left">复制在可视模式下选中的文本</td></tr><tr><td align="left"><code>y + n</code></td><td align="left">复制在可视模式下选中的文本</td></tr><tr><td align="left"><code>yy</code></td><td align="left">复制光标所在整行</td></tr><tr><td align="left"><code>n + yy</code></td><td align="left">复制光标所在的向下 n 行</td></tr><tr><td align="left"><code>y + n + w</code></td><td align="left">复制1(n)个词</td></tr><tr><td align="left"><code>y + n + l</code></td><td align="left">复制光标右边1(n)个字符</td></tr><tr><td align="left"><code>y + n + h</code></td><td align="left">复制光标左边1(n)个字符</td></tr><tr><td align="left"><code>y + $</code></td><td align="left">从光标当前位置复制到行尾</td></tr><tr><td align="left"><code>y + 0</code></td><td align="left">从光标当前位置复制到行首</td></tr><tr><td align="left"><code>y + 0</code></td><td align="left">从光标当前位置复制到行首。</td></tr><tr><td align="left"><code>y + 1 + G</code> 或 <code>y + gg</code></td><td align="left">复制光标以上的所有行</td></tr><tr><td align="left"><code>d</code></td><td align="left">剪切（删除）在可视模式下选中的文本</td></tr><tr><td align="left"><code>dd</code></td><td align="left">剪切（删除）光标所在整行</td></tr><tr><td align="left"><code>n + dd</code></td><td align="left">剪切（删除）光标所在的向下 n 行</td></tr><tr><td align="left"><code>d + n + w</code></td><td align="left">剪切（删除）1(n)个词</td></tr><tr><td align="left"><code>d + n + l</code></td><td align="left">剪切（删除）光标右边1(n)个字符</td></tr><tr><td align="left"><code>d + n + h</code></td><td align="left">剪切（删除）光标左边1(n)个字符</td></tr><tr><td align="left"><code>d + $</code></td><td align="left">从光标当前位置剪切（删除）到行尾</td></tr><tr><td align="left"><code>d + 0</code></td><td align="left">从光标当前位置剪切（删除）到行首</td></tr><tr><td align="left"><code>d + 1 + G</code> 或 <code>d + gg</code></td><td align="left">剪切（删除）光标以上的所有行</td></tr><tr><td align="left"><code>d + G</code></td><td align="left">剪切光标以下的所有行</td></tr><tr><td align="left"><code>p</code></td><td align="left">粘贴光标上一行</td></tr><tr><td align="left"><code>P</code></td><td align="left">粘贴到光标下一行</td></tr><tr><td align="left"><code>u</code></td><td align="left">撤销</td></tr><tr><td align="left"><code>ctrl + r</code></td><td align="left">恢复上一步撤销</td></tr></tbody></table></li><li><p>命令行模式：</p><table><thead><tr><th align="left">命令</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>:w</code></td><td align="left">保存</td></tr><tr><td align="left"><code>:q</code></td><td align="left">退出</td></tr><tr><td align="left"><code>:wq</code> 或 <code>ZZ</code></td><td align="left">保存退出</td></tr><tr><td align="left"><code>:q!</code> 或 <code>ZQ</code></td><td align="left">强制退出（放弃对文档的修改内容）</td></tr><tr><td align="left"><code>:wq!</code></td><td align="left">强制保存退出</td></tr><tr><td align="left"><code>:set nu</code></td><td align="left">显示行号</td></tr><tr><td align="left"><code>:set nonu</code></td><td align="left">不显示行号</td></tr><tr><td align="left"><code>:整数</code></td><td align="left">跳转到该行</td></tr><tr><td align="left"><code>?字符串</code></td><td align="left">在文本中从下至上搜索该字符串</td></tr><tr><td align="left"><code>/字符串</code></td><td align="left">在文本中从上至下搜索该字符串</td></tr><tr><td align="left"><code>:s/one/two</code></td><td align="left">将当前光标所在行的第一个one替换成two</td></tr><tr><td align="left"><code>:s/one/two/g</code></td><td align="left">将当前光标所在行的所有one替换成two</td></tr><tr><td align="left"><code>:%s/one/two/g</code></td><td align="left">将全文中的所有one替换成two</td></tr><tr><td align="left"><code>:m,ny&lt;cr&gt;</code></td><td align="left">复制m行到n行的内容</td></tr><tr><td align="left"><code>:m,nd&lt;cr&gt;</code></td><td align="left">剪切（删除）m行到n行的内容</td></tr><tr><td align="left"><code>:help 命令</code></td><td align="left">查看命令帮助信息</td></tr></tbody></table></li></ol><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><ol><li><p>Vim 的全局配置一般在<code>/etc/vim/vimrc或者/etc/vimrc</code>，对所有用户生效。用户个人的配置在<code>~/.vimrc</code>。</p></li><li><p>配置项一般都有”打开”和”关闭”两个设置。”关闭”就是在”打开”前面加上前缀”no”，双引号开始的行表示注释。</p></li><li><p>加上 <code>:</code> 可在命令行模式运行，一些常用配置：</p> <figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><code class="hljs vim"><span class="hljs-comment">&quot; 显示行号</span><br><span class="hljs-keyword">set</span> <span class="hljs-keyword">number</span><br><br><span class="hljs-comment">&quot; 不显示行号</span><br><span class="hljs-keyword">set</span> nonumber<br><br><span class="hljs-comment">&quot; 不与 Vi 兼容（采用 Vim 自己的操作命令）</span><br><span class="hljs-keyword">set</span> nocompatible<br><br><span class="hljs-comment">&quot; 打开语法高亮。自动识别代码，使用多种颜色显示。</span><br><span class="hljs-keyword">syntax</span> <span class="hljs-keyword">on</span><br><br><span class="hljs-comment">&quot; 在底部显示，当前处于普通模式还是插入模式。</span><br><span class="hljs-keyword">set</span> showmode<br><br><span class="hljs-comment">&quot; 普通模式下，在底部显示，当前键入的指令。</span><br><span class="hljs-keyword">set</span> showcmd<br><br><span class="hljs-comment">&quot; 支持使用鼠标。</span><br><span class="hljs-keyword">set</span> mouse=<span class="hljs-keyword">a</span><br><br><span class="hljs-comment">&quot; 使用 utf-8 编码。</span><br><span class="hljs-keyword">set</span> mouse=<span class="hljs-keyword">a</span><br><br><span class="hljs-comment">&quot; 启用256色。</span><br><span class="hljs-keyword">set</span> t_Co=<span class="hljs-number">256</span><br><br><span class="hljs-comment">&quot; 启文件类型检查，并且载入与该类型对应的缩进规则。</span><br><span class="hljs-keyword">filetype</span> <span class="hljs-built_in">indent</span> <span class="hljs-keyword">on</span><br><br><span class="hljs-comment">&quot; 按下回车键后，下一行的缩进会自动跟上一行的缩进保持一致。</span><br><span class="hljs-keyword">set</span> autoindent<br><br><span class="hljs-comment">&quot; Tab 转为多少个空格。</span><br><span class="hljs-keyword">set</span> softtabstop=<span class="hljs-number">2</span><br><br><span class="hljs-comment">&quot; 设置行宽，即一行显示多少个字符。</span><br><span class="hljs-keyword">set</span> textwidth=<span class="hljs-number">80</span><br><br><span class="hljs-comment">&quot; 光标所在的当前行高亮。</span><br><span class="hljs-keyword">set</span> cursorline<br><br><span class="hljs-comment">&quot; 自动折行，即太长的行分成几行显示。</span><br><span class="hljs-keyword">set</span> wrap<br><br><span class="hljs-comment">&quot; 输入搜索模式时，每输入一个字符，就自动跳到第一个匹配的结果。</span><br><span class="hljs-keyword">set</span> incsearch<br><br><span class="hljs-comment">&quot; 搜索时，高亮显示匹配结果。</span><br><span class="hljs-keyword">set</span> hlsearch<br><br><span class="hljs-comment">&quot; 搜索时忽略大小写。</span><br><span class="hljs-keyword">set</span> ignorecase<br><br><span class="hljs-comment">&quot; 递归的按键映射，按 a 和 c 等于按 b。</span><br>:<span class="hljs-keyword">map</span> <span class="hljs-keyword">a</span> <span class="hljs-keyword">b</span><br>:<span class="hljs-keyword">map</span> <span class="hljs-keyword">c</span> <span class="hljs-keyword">a</span><br>    <br><span class="hljs-comment">&quot; 非递归的按键映射，表示按 d 等于按 a。</span><br>:<span class="hljs-keyword">noremap</span> d <span class="hljs-keyword">a</span><br></code></pre></td></tr></table></figure></li></ol><h1 id="插件"><a href="#插件" class="headerlink" title="插件"></a>插件</h1><ol><li><p>Unix 安装 <a href="https://github.com/junegunn/vim-plug">vim-plus</a>（一个极简的Vim插件管理器）：</p><pre><code class="hljs"> curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim</code></pre></li><li><p>配置：</p><p> 在~&#x2F;.vimrc中添加要下载的vim插件，然后重启。    </p> <figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs vim"><span class="hljs-comment">&quot; 开始标签</span><br><br><span class="hljs-keyword">call</span> plug#begin(<span class="hljs-string">&#x27;~/.vim/plugged&#x27;</span>)<br><br><span class="hljs-comment">&quot; 单引号内些上你需要安装的插件</span><br><br>    Plug <span class="hljs-string">&#x27;xxx&#x27;</span><br><br><span class="hljs-comment">&quot; 结束标签</span><br><br><span class="hljs-keyword">call</span> plug#end()<br></code></pre></td></tr></table></figure></li><li><p>使用和卸载：</p><p> 在命令行模式输入命令使用插件。</p><table><thead><tr><th align="left">命令</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>:PlugInstall [name ...] [#threads]</code></td><td align="left">安装插件</td></tr><tr><td align="left"><code>:PlugUpdate [name ...] [#threads]</code></td><td align="left">安装或更新插件</td></tr><tr><td align="left"><code>:PlugClean[!]</code></td><td align="left">删除未列出的插件</td></tr><tr><td align="left"><code>:PlugUpgrade</code></td><td align="left">升级vim-plug</td></tr><tr><td align="left"><code>:PlugStatus</code></td><td align="left">检查插件状态</td></tr><tr><td align="left"><code>:PlugDiff</code></td><td align="left">检查来自先前更新的更改以及未决的更改</td></tr><tr><td align="left"><code>:PlugSnapshot[!] [output path]</code></td><td align="left">生成脚本以还原插件的当前快照</td></tr></tbody></table><p> 更多插件参见 <a href="https://vimawesome.com/">vim Awesome</a>。</p></li></ol><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://www.linuxprobe.com/chapter-04.html">Vim编辑器与Shell命令脚本</a></li><li><a href="https://www.runoob.com/linux/linux-vim.html">Linux vi&#x2F;vim</a></li><li><a href="https://zhuanlan.zhihu.com/p/51440836">史上最全的Vim命令</a></li><li><a href="http://www.ruanyifeng.com/blog/2018/09/vimrc.html">Vim 配置入门</a></li><li><a href="https://github.com/junegunn/vim-plug">vim-plus</a></li><li><a href="https://vimawesome.com/">vim Awesome</a></li><li><a href="https://github.com/vim-china/hello-vim/blob/master/quick-start-guide.md">Vim 入门教程</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;模式&quot;&gt;&lt;a href=&quot;#模式&quot; class=&quot;headerlink&quot; title=&quot;模式&quot;&gt;&lt;/a&gt;模式&lt;/h1&gt;&lt;p&gt;在其他模式下使用 &lt;code&gt;Esc&lt;/code&gt; 切换回普通模式，命令行模式下使用 &lt;code&gt;:命令&lt;/code&gt; + &lt;code&gt;En</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Linux" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Linux/"/>
    
    
    <category term="Vim" scheme="http://www.loquy.cn/tags/Vim/"/>
    
    <category term="Linux" scheme="http://www.loquy.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Yii 中活动记录（Active Record）类的使用</title>
    <link href="http://www.loquy.cn/posts/6a73a53a.html"/>
    <id>http://www.loquy.cn/posts/6a73a53a.html</id>
    <published>2020-08-21T03:33:12.000Z</published>
    <updated>2020-08-21T09:50:12.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Yii中活动记录（Active-Record）类的使用"><a href="#Yii中活动记录（Active-Record）类的使用" class="headerlink" title="Yii中活动记录（Active Record）类的使用"></a>Yii中活动记录（Active Record）类的使用</h1><h2 id="查询数据"><a href="#查询数据" class="headerlink" title="查询数据"></a>查询数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">/** </span><br><span class="hljs-comment">定义 Active Record 类后，你可以从相应的数据库表中查询数据。 查询过程大致如下三个步骤：</span><br><span class="hljs-comment">1.通过 yii\db\ActiveRecord::find() 方法创建一个新的查询生成器对象；</span><br><span class="hljs-comment">2.使用查询生成器的构建方法来构建你的查询；</span><br><span class="hljs-comment">3.调用查询生成器的查询方法来取出数据到 Active Record 实例中。</span><br><span class="hljs-comment">正如你看到的，是不是跟查询生成器的步骤差不多。 唯一有区别的地方在于你用 yii\db\ActiveRecord::find() 去获得一个新的查询生成器对象，这个对象是 yii\db\ActiveQuery， 而不是使用 new 操作符创建一个查询生成器对象。 </span><br><span class="hljs-comment">下面是一些例子，介绍如何使用 Active Query 查询数据：</span><br><span class="hljs-comment">**/</span><br><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123 </span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-number">123</span>])-&gt;<span class="hljs-title function_ invoke__">one</span>();<br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>([<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-number">123</span>]);<br><br><span class="hljs-comment">// 取回所有活跃客户并以他们的 ID 排序：</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Customer</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>])<br>    -&gt;<span class="hljs-title function_ invoke__">orderBy</span>(<span class="hljs-string">&#x27;id&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-comment">// 返回 id 是 100, 101, 123, 124 的客户</span><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` IN (100, 101, 123, 124)</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findAll</span>([<span class="hljs-number">100</span>, <span class="hljs-number">101</span>, <span class="hljs-number">123</span>, <span class="hljs-number">124</span>]);<br><br><span class="hljs-comment">// 返回 id 是 123 的活跃客户</span><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123 AND `status` = 1</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>([<br>    <span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-number">123</span>,<br>    <span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Customer</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>,<br>]);<br><br><span class="hljs-comment">// 返回所有不活跃的客户</span><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `status` = 0</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findAll</span>([<br>    <span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Customer</span>::<span class="hljs-variable constant_">STATUS_INACTIVE</span>,<br>]);<br><br><span class="hljs-comment">// 取回活跃客户的数量：</span><br><span class="hljs-comment">// SELECT COUNT(*) FROM `customer` WHERE `status` = 1</span><br><span class="hljs-variable">$count</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Customer</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>])<br>    -&gt;<span class="hljs-title function_ invoke__">count</span>();<br><br><span class="hljs-comment">// 以客户 ID 索引结果集：</span><br><span class="hljs-comment">// SELECT * FROM `customer`</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">indexBy</span>(<span class="hljs-string">&#x27;id&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-comment">// 警告： 如果你需要将用户输入传递给这些方法，请确保输入值是标量或者是 数组条件，确保数组结构不能被外部所改变：</span><br><br><span class="hljs-comment">// yii\web\Controller 确保了 $id 是标量</span><br><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionView</span>(<span class="hljs-params"><span class="hljs-variable">$id</span></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-variable">$model</span> = <span class="hljs-title class_">Post</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-variable">$id</span>);<br>    <span class="hljs-comment">// ...</span><br>&#125;<br><br><span class="hljs-comment">// 明确了指定要搜索的列，在此处传递标量或数组将始终只是查找出单个记录而已</span><br><span class="hljs-variable">$model</span> = <span class="hljs-title class_">Post</span>::<span class="hljs-title function_ invoke__">findOne</span>([<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-title class_">Yii</span>::<span class="hljs-variable">$app</span>-&gt;request-&gt;<span class="hljs-title function_ invoke__">get</span>(<span class="hljs-string">&#x27;id&#x27;</span>)]);<br><br><span class="hljs-comment">// 不要使用下面的代码！可以注入一个数组条件来匹配任意列的值！</span><br><span class="hljs-variable">$model</span> = <span class="hljs-title class_">Post</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-title class_">Yii</span>::<span class="hljs-variable">$app</span>-&gt;request-&gt;<span class="hljs-title function_ invoke__">get</span>(<span class="hljs-string">&#x27;id&#x27;</span>));<br></code></pre></td></tr></table></figure><h2 id="数据转换"><a href="#数据转换" class="headerlink" title="数据转换"></a>数据转换</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">// ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBirthdayText</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">date</span>(<span class="hljs-string">&#x27;Y/m/d&#x27;</span>, <span class="hljs-variable">$this</span>-&gt;birthday);<br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setBirthdayText</span>(<span class="hljs-params"><span class="hljs-variable">$value</span></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable language_">$this</span>-&gt;birthday = <span class="hljs-title function_ invoke__">strtotime</span>(<span class="hljs-variable">$value</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 访问$customer-&gt;birthdayText</span><br></code></pre></td></tr></table></figure><h2 id="以数组形式获取数据"><a href="#以数组形式获取数据" class="headerlink" title="以数组形式获取数据"></a>以数组形式获取数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 返回所有客户</span><br><span class="hljs-comment">// 每个客户返回一个关联数组</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">asArray</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-comment">// 提示： 虽然这种方法可以节省内存并提高性能，但它更靠近较低的 DB 抽象层 你将失去大部分的 Active Record 提供的功能。 一个非常重要的区别在于列值的数据类型。 当您在 Active Record 实例中返回数据时，列值将根据实际列类型，自动类型转换； 然而，当您以数组返回数据时，列值将为 字符串（因为它们是没有处理过的 PDO 的结果），不管它们的实际列是什么类型。</span><br></code></pre></td></tr></table></figure><h2 id="批量获取数据"><a href="#批量获取数据" class="headerlink" title="批量获取数据"></a>批量获取数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 每次获取 10 条客户数据</span><br><span class="hljs-keyword">foreach</span> (<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">batch</span>(<span class="hljs-number">10</span>) <span class="hljs-keyword">as</span> <span class="hljs-variable">$customers</span>) &#123;<br>    <span class="hljs-comment">// $customers 是个最多拥有 10 条数据的数组</span><br>&#125;<br><br><span class="hljs-comment">// 每次获取 10 条客户数据，然后一条一条迭代它们</span><br><span class="hljs-keyword">foreach</span> (<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">each</span>(<span class="hljs-number">10</span>) <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) &#123;<br>    <span class="hljs-comment">// $customer 是个 `Customer` 对象</span><br>&#125;<br><br><span class="hljs-comment">// 贪婪加载模式的批处理查询</span><br><span class="hljs-keyword">foreach</span> (<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;orders&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">each</span>() <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) &#123;<br>    <span class="hljs-comment">// $customer 是个 `Customer` 对象，并附带关联的 `&#x27;orders&#x27;`</span><br>&#125;<br></code></pre></td></tr></table></figure><h2 id="保存数据"><a href="#保存数据" class="headerlink" title="保存数据"></a>保存数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 插入新记录</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Customer</span>();<br><span class="hljs-variable">$customer</span>-&gt;name = <span class="hljs-string">&#x27;James&#x27;</span>;<br><span class="hljs-variable">$customer</span>-&gt;email = <span class="hljs-string">&#x27;james@example.com&#x27;</span>;<br><span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();<br><br><span class="hljs-comment">// 更新已存在的记录</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><span class="hljs-variable">$customer</span>-&gt;email = <span class="hljs-string">&#x27;james@newexample.com&#x27;</span>;<br><span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();<br><br><span class="hljs-comment">// save() 方法可能插入或者更新表的记录，这取决于 Active Record 实例的状态。 如果实例通过 new 操作符实例化，调用 save() 方法将插入新记录； 如果实例是一个查询方法的结果，调用 save() 方法 将更新这个实例对应的表记录行。</span><br></code></pre></td></tr></table></figure><h2 id="数据验证"><a href="#数据验证" class="headerlink" title="数据验证"></a>数据验证</h2><pre><code class="hljs">因为 yii\db\ActiveRecord 继承于 yii\base\Model，它共享相同的 输入验证 功能。 你可以通过重写 rules() 方法声明验证规则并执行， 通过调用 validate() 方法进行数据验证。当你调用 save() 时，默认情况下会自动调用 validate()。 只有当验证通过时，它才会  真正地保存数据; 否则将简单地返回 false， 您可以检查 errors 属性来获取验证过程的错误消息。提示： 如果你确定你的数据不需要验证（比如说数据来自可信的场景）， 你可以调用 save(false) 来跳过验证过程。</code></pre><h2 id="快赋值"><a href="#快赋值" class="headerlink" title="快赋值"></a>快赋值</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs php">  <span class="hljs-comment">// 和普通的 模型 一样，你亦可以享受 Active Record 实例的 块赋值 特性。 使用此功能，您可以在单个 PHP 语句中，给 Active Record 实例的多个属性批量赋值， 如下所示。 记住，只有 安全属性 才可以批量赋值。</span><br><br><span class="hljs-variable">$values</span> = [<br>    <span class="hljs-string">&#x27;name&#x27;</span> =&gt; <span class="hljs-string">&#x27;James&#x27;</span>,<br>    <span class="hljs-string">&#x27;email&#x27;</span> =&gt; <span class="hljs-string">&#x27;james@example.com&#x27;</span>,<br>];<br><br><span class="hljs-variable">$customer</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Customer</span>();<br><br><span class="hljs-variable">$customer</span>-&gt;attributes = <span class="hljs-variable">$values</span>;<br><span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();<br></code></pre></td></tr></table></figure><h2 id="更新计数"><a href="#更新计数" class="headerlink" title="更新计数"></a>更新计数</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 在数据库表中增加或减少一个字段的值是个常见的任务。我们将这些列称为“计数列”。 您可以使用 updateCounters() 更新一个或多个计数列。 例如，</span><br>    <br><span class="hljs-variable">$post</span> = <span class="hljs-title class_">Post</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">100</span>);<br><br><span class="hljs-comment">// UPDATE `post` SET `view_count` = `view_count` + 1 WHERE `id` = 100</span><br><span class="hljs-variable">$post</span>-&gt;<span class="hljs-title function_ invoke__">updateCounters</span>([<span class="hljs-string">&#x27;view_count&#x27;</span> =&gt; <span class="hljs-number">1</span>]);<br><br><span class="hljs-comment">// 同样，你可以调用 updateAllCounters() 同时更新多条记录的计数列</span><br><span class="hljs-comment">// UPDATE `customer` SET `age` = `age` + 1</span><br><span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">updateAllCounters</span>([<span class="hljs-string">&#x27;age&#x27;</span> =&gt; <span class="hljs-number">1</span>]);<br></code></pre></td></tr></table></figure><h2 id="更新多个数据行"><a href="#更新多个数据行" class="headerlink" title="更新多个数据行"></a>更新多个数据行</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// UPDATE `customer` SET `status` = 1 WHERE `email` LIKE `%@example.com%`</span><br><span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">updateAll</span>([<span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Customer</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>], [<span class="hljs-string">&#x27;like&#x27;</span>, <span class="hljs-string">&#x27;email&#x27;</span>, <span class="hljs-string">&#x27;@example.com&#x27;</span>]);<br></code></pre></td></tr></table></figure><h2 id="删除数据"><a href="#删除数据" class="headerlink" title="删除数据"></a>删除数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 要删除单行数据，首先获取与该行对应的 Active Record 实例，然后调用 yii\db\ActiveRecord::delete() 方法。</span><br><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">delete</span>();<br><br><span class="hljs-comment">// 你可以调用 yii\db\ActiveRecord::deleteAll() 方法删除多行甚至全部的数据。例如,</span><br><br><span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">deleteAll</span>([<span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Customer</span>::<span class="hljs-variable constant_">STATUS_INACTIVE</span>]);<br></code></pre></td></tr></table></figure><h2 id="事务操作"><a href="#事务操作" class="headerlink" title="事务操作"></a>事务操作</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><br><span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">getDb</span>()-&gt;<span class="hljs-title function_ invoke__">transaction</span>(function(<span class="hljs-variable">$db</span>) <span class="hljs-keyword">use</span> ($<span class="hljs-title">customer</span>) &#123;<br>    $<span class="hljs-title">customer</span>-&gt;<span class="hljs-title">id</span> = 200;<br>    <span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();<br>    <span class="hljs-comment">// ...其他 DB 操作...</span><br>&#125;);<br>    <br><span class="hljs-comment">// 或者</span><br><br><span class="hljs-variable">$transaction</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">getDb</span>()-&gt;<span class="hljs-title function_ invoke__">beginTransaction</span>();<br><span class="hljs-keyword">try</span> &#123;<br>    <span class="hljs-variable">$customer</span>-&gt;id = <span class="hljs-number">200</span>;<br>    <span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();<br>    <span class="hljs-comment">// ...other DB operations...</span><br>    <span class="hljs-variable">$transaction</span>-&gt;<span class="hljs-title function_ invoke__">commit</span>();<br>&#125; <span class="hljs-keyword">catch</span>(\<span class="hljs-built_in">Exception</span> <span class="hljs-variable">$e</span>) &#123;<br>    <span class="hljs-variable">$transaction</span>-&gt;<span class="hljs-title function_ invoke__">rollBack</span>();<br>    <span class="hljs-keyword">throw</span> <span class="hljs-variable">$e</span>;<br>&#125; <span class="hljs-keyword">catch</span>(\<span class="hljs-built_in">Throwable</span> <span class="hljs-variable">$e</span>) &#123;<br>    <span class="hljs-variable">$transaction</span>-&gt;<span class="hljs-title function_ invoke__">rollBack</span>();<br>    <span class="hljs-keyword">throw</span> <span class="hljs-variable">$e</span>;<br>&#125;<br>    <br>    <span class="hljs-comment">// 提示： 在上面的代码中，我们有两个catch块用于兼容 PHP 5.x 和 PHP 7.x。 \Exception 继承于 \Throwable interface 由于 PHP 7.0 的改动，如果您的应用程序仅使用 PHP 7.0 及更高版本，您可以跳过 \Exception 部分。</span><br></code></pre></td></tr></table></figure><h2 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h2><pre><code class="hljs">乐观锁是一种防止此冲突的方法：一行数据 同时被多个用户更新。例如，同一时间内，用户 A 和用户 B 都在编辑 相同的 wiki 文章。用户 A 保存他的编辑后，用户 B 也点击“保存”按钮来 保存他的编辑。实际上，用户 B 正在处理的是过时版本的文章， 因此最好是，想办法阻止他保存文章并向他提示一些信息。乐观锁通过使用一个字段来记录每行的版本号来解决上述问题。 当使用过时的版本号保存一行数据时，yii\db\StaleObjectException 异常 将被抛出，这阻止了该行的保存。乐观锁只支持更新 yii\db\ActiveRecord::update() 或者删除 yii\db\ActiveRecord::delete() 已经存在的单条数据行。使用乐观锁的步骤，1.在与 Active Record 类相关联的 DB 表中创建一个列，以存储每行的版本号。 这个列应当是长整型（在 MySQL 中是 BIGINT DEFAULT 0）。2.重写 yii\db\ActiveRecord::optimisticLock() 方法返回这个列的命名。3.在你的 Model 类里实现 OptimisticLockBehavior 行为（注：这个行为类在 2.0.16 版本加入），以便从请求参数里自动解析这个列的值。 然后从验证规则中删除 version 属性，因为 OptimisticLockBehavior 已经处理它了.4.在用于用户填写的 Web 表单中，添加一个隐藏字段（hidden field）来存储正在更新的行的当前版本号。5.在使用 Active Record 更新数据的控制器动作中，要捕获（try/catch） yii\db\StaleObjectException 异常。 实现一些业务逻辑来解决冲突（例如合并更改，提示陈旧的数据等等）。例如，假定版本列被命名为 version。您可以使用下面的代码来实现乐观锁。</code></pre><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// ------ 视图层代码 -------</span><br><br><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\<span class="hljs-title">helpers</span>\<span class="hljs-title">Html</span>;<br><br><span class="hljs-comment">// ...其他输入栏</span><br><span class="hljs-keyword">echo</span> <span class="hljs-title class_">Html</span>::<span class="hljs-title function_ invoke__">activeHiddenInput</span>(<span class="hljs-variable">$model</span>, <span class="hljs-string">&#x27;version&#x27;</span>);<br><br><br><span class="hljs-comment">// ------ 控制器代码 -------</span><br><br><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">StaleObjectException</span>;<br><br><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionUpdate</span>(<span class="hljs-params"><span class="hljs-variable">$id</span></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-variable">$model</span> = <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">findModel</span>(<span class="hljs-variable">$id</span>);<br><br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-variable">$model</span>-&gt;<span class="hljs-title function_ invoke__">load</span>(<span class="hljs-title class_">Yii</span>::<span class="hljs-variable">$app</span>-&gt;request-&gt;<span class="hljs-title function_ invoke__">post</span>()) &amp;&amp; <span class="hljs-variable">$model</span>-&gt;<span class="hljs-title function_ invoke__">save</span>()) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">redirect</span>([<span class="hljs-string">&#x27;view&#x27;</span>, <span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-variable">$model</span>-&gt;id]);<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">render</span>(<span class="hljs-string">&#x27;update&#x27;</span>, [<br>                <span class="hljs-string">&#x27;model&#x27;</span> =&gt; <span class="hljs-variable">$model</span>,<br>            ]);<br>        &#125;<br>    &#125; <span class="hljs-keyword">catch</span> (StaleObjectException <span class="hljs-variable">$e</span>) &#123;<br>        <span class="hljs-comment">// 解决冲突的代码</span><br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// ------ Model 代码 -------</span><br><br><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\<span class="hljs-title">behaviors</span>\<span class="hljs-title">OptimisticLockBehavior</span>;<br><br><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">behaviors</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-keyword">return</span> [<br>        <span class="hljs-title class_">OptimisticLockBehavior</span>::<span class="hljs-title function_ invoke__">className</span>(),<br>    ];<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="使用关联数据"><a href="#使用关联数据" class="headerlink" title="使用关联数据"></a>使用关联数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 声明关联关系</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">// ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">// ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCustomer</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasOne</span>(<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-string">&#x27;customer_id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">/** 上述的代码中，我们为 Customer 类声明了一个 orders 关联， 和为 Order 声明了一个 customer 关联。</span><br><span class="hljs-comment"></span><br><span class="hljs-comment"> 每个关联方法必须这样命名：getXyz。然后我们通过 xyz（首字母小写）调用这个关联名。 请注意关联名是大小写敏感的。</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">当声明一个关联关系的时候，必须指定好以下的信息：</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">关联的对应关系：通过调用 hasMany() 或者 hasOne() 指定。在上面的例子中，您可以很容易看出这样的关联声明： 一个客户可以有很多订单，而每个订单只有一个客户。</span><br><span class="hljs-comment">相关联 Active Record 类名：用来指定为 hasMany() 或者 hasOne() 方法的第一个参数。 推荐的做法是调用 Xyz::className() 来获取类名称的字符串，以便您 可以使用 IDE 的自动补全，以及让编译阶段的错误检测生效。</span><br><span class="hljs-comment">两组数据的关联列：用以指定两组数据相关的列（hasOne()/hasMany() 的第二个参数）。 数组的值填的是主数据的列（当前要声明关联的 Active Record 类为主数据）， 而数组的键要填的是相关数据的列。</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">一个简单的口诀，先附表的主键，后主表的主键。 正如上面的例子，customer_id 是 Order 的属性，而 id是 Customer 的属性。 （译者注：hasMany() 的第二个参数，这个数组键值顺序不要弄反了）**/</span><br>    <br><span class="hljs-comment">// 访问关联数据</span><br>    <br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123</span><br><span class="hljs-comment">// $orders 是由 Order 类组成的数组</span><br><span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;orders;<br><br><span class="hljs-comment">//  当你通过 getter 方法 getXyz() 声明了一个叫 xyz 的关联属性，你就可以像 属性 那样访问 xyz。注意这个命名是区分大小写的。</span><br><br><span class="hljs-comment">// 提示： 虽然这个概念跟 这个 属性 特性很像， 但是还是有一个很重要的区别。普通对象属性的属性值与其定义的 getter 方法的类型是相同的。 而关联方法返回的是一个 yii\db\ActiveQuery 活动查询生成器的实例。只有当访问关联属性的的时候， 才会返回 yii\db\ActiveRecord Active Record 实例，或者 Active Record 实例组成的数组。</span><br><br><span class="hljs-variable">$customer</span>-&gt;orders; <span class="hljs-comment">// 获得 `Order` 对象的数组</span><br><span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">getOrders</span>(); <span class="hljs-comment">// 返回 ActiveQuery 类的实例</span><br></code></pre></td></tr></table></figure><h2 id="动态关联查询"><a href="#动态关联查询" class="headerlink" title="动态关联查询"></a>动态关联查询</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123 AND `subtotal` &gt; 200 ORDER BY `id`</span><br><span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">getOrders</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;&gt;&#x27;</span>, <span class="hljs-string">&#x27;subtotal&#x27;</span>, <span class="hljs-number">200</span>])<br>    -&gt;<span class="hljs-title function_ invoke__">orderBy</span>(<span class="hljs-string">&#x27;id&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBigOrders</span>(<span class="hljs-params"><span class="hljs-variable">$threshold</span> = <span class="hljs-number">100</span></span>) // 老司机的提醒机的提醒<span class="hljs-title">threshold</span> 参数一定一定要给个默认值一定要给个默认值</span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>])<br>            -&gt;<span class="hljs-title function_ invoke__">where</span>(<span class="hljs-string">&#x27;subtotal &gt; :threshold&#x27;</span>, [<span class="hljs-string">&#x27;:threshold&#x27;</span> =&gt; <span class="hljs-variable">$threshold</span>])<br>            -&gt;<span class="hljs-title function_ invoke__">orderBy</span>(<span class="hljs-string">&#x27;id&#x27;</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 然后你就可以执行以下关联查询：</span><br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123 AND `subtotal` &gt; 200 ORDER BY `id`</span><br><span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">getBigOrders</span>(<span class="hljs-number">200</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123 AND `subtotal` &gt; 100 ORDER BY `id`</span><br><span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;bigOrders;<br></code></pre></td></tr></table></figure><h2 id="中间表关联"><a href="#中间表关联" class="headerlink" title="中间表关联"></a>中间表关联</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 在数据库建模中，当两个关联表之间的对应关系是多对多时， 通常会引入一个连接表。例如，order 表 和 item 表可以通过名为 order_item 的连接表相关联。一个 order 将关联多个 order items， 而一个 order item 也会关联到多个 orders。</span><br><br><span class="hljs-comment">// 当声明这种表关联后，您可以调用 via() 或 viaTable() 指明连接表。via() 和 viaTable() 之间的区别是 前者是根据现有的关联名称来指定连接表，而后者直接使用 连接表。例如，</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getItems</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Item</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-string">&#x27;item_id&#x27;</span>])<br>            -&gt;<span class="hljs-title function_ invoke__">viaTable</span>(<span class="hljs-string">&#x27;order_item&#x27;</span>, [<span class="hljs-string">&#x27;order_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 或者,</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrderItems</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">OrderItem</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;order_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getItems</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Item</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-string">&#x27;item_id&#x27;</span>])<br>            -&gt;<span class="hljs-title function_ invoke__">via</span>(<span class="hljs-string">&#x27;orderItems&#x27;</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 使用连接表声明的关联和正常声明的关联是等同的，例如，</span><br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `id` = 100</span><br><span class="hljs-variable">$order</span> = <span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">100</span>);<br><br><span class="hljs-comment">// SELECT * FROM `order_item` WHERE `order_id` = 100</span><br><span class="hljs-comment">// SELECT * FROM `item` WHERE `item_id` IN (...)</span><br><span class="hljs-comment">// 返回 Item 类组成的数组</span><br><span class="hljs-variable">$items</span> = <span class="hljs-variable">$order</span>-&gt;items;<br></code></pre></td></tr></table></figure><h2 id="通过多个表来连接关联声明"><a href="#通过多个表来连接关联声明" class="headerlink" title="通过多个表来连接关联声明"></a>通过多个表来连接关联声明</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 通过使用 via() 方法，它还可以通过多个表来定义关联声明。 再考虑考虑上面的例子，我们有 Customer，Order 和 Item 类。 我们可以添加一个关联关系到 Customer 类，这个关联可以列出了 Customer（客户） 的订单下放置的所有 Item（商品）， 这个关联命名为 getPurchasedItems()，关联声明如下代码示例所示：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">// ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPurchasedItems</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-comment">// 客户的商品，将 Item 中的 &#x27;id&#x27; 列与 OrderItem 中的 &#x27;item_id&#x27; 相匹配</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Item</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-string">&#x27;item_id&#x27;</span>])<br>                    -&gt;<span class="hljs-title function_ invoke__">via</span>(<span class="hljs-string">&#x27;orderItems&#x27;</span>);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrderItems</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-comment">// 客户订单中的商品，将 `Order` 的 &#x27;id&#x27; 列和 OrderItem 的 &#x27;order_id&#x27; 列相匹配</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">OrderItem</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;order_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>])<br>                    -&gt;<span class="hljs-title function_ invoke__">via</span>(<span class="hljs-string">&#x27;orders&#x27;</span>);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-comment">// 见上述列子</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h2 id="延迟加载和即时加载"><a href="#延迟加载和即时加载" class="headerlink" title="延迟加载和即时加载"></a>延迟加载和即时加载</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 在 访问关联数据 中，我们解释说可以像问正常的对象属性那样 访问 Active Record 实例的关联属性。SQL 语句仅在 你第一次访问关联属性时执行。我们称这种关联数据访问方法为 延迟加载。 例如，</span><br><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123</span><br><span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;orders;<br><br><span class="hljs-comment">// 没有 SQL 语句被执行</span><br><span class="hljs-variable">$orders2</span> = <span class="hljs-variable">$customer</span>-&gt;orders;<br><span class="hljs-comment">// 延迟加载使用非常方便。但是，当你需要访问相同的具有多个 Active Record 实例的关联属性时， 可能会遇到性能问题。请思考一下以下代码示例。 有多少 SQL 语句会被执行？</span><br><br><span class="hljs-comment">// SELECT * FROM `customer` LIMIT 100</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">limit</span>(<span class="hljs-number">100</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$customers</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) &#123;<br>    <span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = ...</span><br>    <span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;orders;<br>&#125;<br><span class="hljs-comment">// 你瞅瞅，上面的代码会产生 101 次 SQL 查询！ 这是因为每次你访问 for 循环中不同的 Customer 对象的 orders 关联属性时，SQL 语句 都会被执行一次。</span><br><br><span class="hljs-comment">// 为了解决上述的性能问题，你可以使用所谓的 即时加载，如下所示，</span><br><br><span class="hljs-comment">// SELECT * FROM `customer` LIMIT 100;</span><br><span class="hljs-comment">// SELECT * FROM `orders` WHERE `customer_id` IN (...)</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;orders&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">limit</span>(<span class="hljs-number">100</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$customers</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) &#123;<br>    <span class="hljs-comment">// 没有任何的 SQL 执行</span><br>    <span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>-&gt;orders;<br>&#125;<br><span class="hljs-comment">// 通过调用 yii\db\ActiveQuery::with() 方法，你使 Active Record 在一条 SQL 语句里就返回了这 100 位客户的订单。 结果就是，你把要执行的 SQL 语句从 101 减少到 2 条！</span><br><br><span class="hljs-comment">// 你可以即时加载一个或多个关联。 你甚至可以即时加载 嵌套关联 。嵌套关联是一种 在相关的 Active Record 类中声明的关联。例如，Customer 通过 orders 关联属性 与 Order 相关联， Order 与 Item 通过 items 关联属性相关联。 当查询 Customer 时，您可以即时加载 通过嵌套关联符 orders.items 关联的 items。</span><br><br><span class="hljs-comment">// 以下代码展示了 with() 的各种用法。我们假设 Customer 类 有两个关联 orders 和 country，而 Order 类有一个关联 items。</span><br><br><span class="hljs-comment">//  即时加载 &quot;orders&quot; and &quot;country&quot;</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;orders&#x27;</span>, <span class="hljs-string">&#x27;country&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 等同于使用数组语法 如下</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>([<span class="hljs-string">&#x27;orders&#x27;</span>, <span class="hljs-string">&#x27;country&#x27;</span>])-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 没有任何的 SQL 执行</span><br><span class="hljs-variable">$orders</span>= <span class="hljs-variable">$customers</span>[<span class="hljs-number">0</span>]-&gt;orders;<br><span class="hljs-comment">// 没有任何的 SQL 执行</span><br><span class="hljs-variable">$country</span> = <span class="hljs-variable">$customers</span>[<span class="hljs-number">0</span>]-&gt;country;<br><br><span class="hljs-comment">// 即时加载“订单”和嵌套关系“orders.items”</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;orders.items&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 访问第一个客户的第一个订单中的商品</span><br><span class="hljs-comment">// 没有 SQL 查询执行</span><br><span class="hljs-variable">$items</span> = <span class="hljs-variable">$customers</span>[<span class="hljs-number">0</span>]-&gt;orders[<span class="hljs-number">0</span>]-&gt;items;<br><span class="hljs-comment">// 你也可以即时加载更深的嵌套关联，比如 a.b.c.d。所有的父关联都会被即时加载。 那就是, 当你调用 with() 来 with a.b.c.d, 你将即时加载 a, a.b, a.b.c and a.b.c.d。</span><br><br><span class="hljs-comment">// 提示： 一般来说，当即时加载 N 个关联，另有 M 个关联 通过 连接表 声明，则会有 N+M+1 条 SQL 语句被执行。 请注意这样的的嵌套关联 a.b.c.d 算四个关联。</span><br><br><span class="hljs-comment">// 当即时加载一个关联，你可以通过匿名函数自定义相应的关联查询。 例如，</span><br><br><span class="hljs-comment">// 查找所有客户，并带上他们国家和活跃订单</span><br><span class="hljs-comment">// SELECT * FROM `customer`</span><br><span class="hljs-comment">// SELECT * FROM `country` WHERE `id` IN (...)</span><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` IN (...) AND `status` = 1</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>([<br>    <span class="hljs-string">&#x27;country&#x27;</span>,<br>    <span class="hljs-string">&#x27;orders&#x27;</span> =&gt; function (<span class="hljs-variable">$query</span>) &#123;<br>        <span class="hljs-variable">$query</span>-&gt;<span class="hljs-title function_ invoke__">andWhere</span>([<span class="hljs-string">&#x27;status&#x27;</span> =&gt; <span class="hljs-title class_">Order</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>]);<br>    &#125;,<br>])-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 自定义关联查询时，应该将关联名称指定为数组的键 并使用匿名函数作为相应的数组的值。匿名函数将接受一个 $query 参数 它用于表示这个自定义的关联执行关联查询的 yii\db\ActiveQuery 对象。 在上面的代码示例中，我们通过附加一个关于订单状态的附加条件来修改关联查询。</span><br><br><span class="hljs-comment">// 提示： 如果你在即时加载的关联中调用 select() 方法，你要确保 在关联声明中引用的列必须被 select。否则，相应的模型（Models）可能 无法加载。例如，</span><br><br><span class="hljs-variable">$orders</span> = <span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">select</span>([<span class="hljs-string">&#x27;id&#x27;</span>, <span class="hljs-string">&#x27;amount&#x27;</span>])-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;customer&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// $orders[0]-&gt;customer 会一直是 `null`。你应该这样写，以解决这个问题：</span><br><span class="hljs-variable">$orders</span> = <span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">select</span>([<span class="hljs-string">&#x27;id&#x27;</span>, <span class="hljs-string">&#x27;amount&#x27;</span>, <span class="hljs-string">&#x27;customer_id&#x27;</span>])-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;cus</span><br></code></pre></td></tr></table></figure><h2 id="关联关系的-JOIN-查询"><a href="#关联关系的-JOIN-查询" class="headerlink" title="关联关系的 JOIN 查询"></a>关联关系的 JOIN 查询</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 提示： 这小节的内容仅仅适用于关系数据库， 比如 MySQL，PostgreSQL 等等。</span><br><br><span class="hljs-comment">// 到目前为止，我们所介绍的关联查询，仅仅是使用主表列 去查询主表数据。实际应用中，我们经常需要在关联表中使用这些列。例如， 我们可能要取出至少有一个活跃订单的客户。为了解决这个问题，我们可以 构建一个 join 查询，如下所示：</span><br><br><span class="hljs-comment">// SELECT `customer`.* FROM `customer`</span><br><span class="hljs-comment">// LEFT JOIN `order` ON `order`.`customer_id` = `customer`.`id`</span><br><span class="hljs-comment">// WHERE `order`.`status` = 1</span><br><span class="hljs-comment">// </span><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` IN (...)</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">select</span>(<span class="hljs-string">&#x27;customer.*&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">leftJoin</span>(<span class="hljs-string">&#x27;order&#x27;</span>, <span class="hljs-string">&#x27;`order`.`customer_id` = `customer`.`id`&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;order.status&#x27;</span> =&gt; <span class="hljs-title class_">Order</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>])<br>    -&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;orders&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 提示： 在构建涉及 JOIN SQL 语句的连接查询时，清除列名的歧义很重要。 通常的做法是将表名称作为前缀加到对应的列名称前。</span><br><br><span class="hljs-comment">// 但是，更好的方法是通过调用 yii\db\ActiveQuery::joinWith() 来利用已存在的关联声明：</span><br><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">joinWith</span>(<span class="hljs-string">&#x27;orders&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;order.status&#x27;</span> =&gt; <span class="hljs-title class_">Order</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>])<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 两种方法都执行相同的 SQL 语句集。然而，后一种方法更干净、简洁。</span><br><br><span class="hljs-comment">// 默认的，joinWith() 会使用 LEFT JOIN 去连接主表和关联表。 你可以通过 $joinType 参数指定不同的连接类型（比如 RIGHT JOIN）。 如果你想要的连接类型是 INNER JOIN，你可以直接用 innerJoinWith() 方法代替。</span><br><br><span class="hljs-comment">// 调用 joinWith() 方法会默认 即时加载 相应的关联数据。 如果你不需要那些关联数据，你可以指定它的第二个参数 $eagerLoading 为 false。</span><br><br><span class="hljs-comment">// 注意： 即使在启用即时加载的情况下使用 joinWith() 或 innerJoinWith()， 相应的关联数据也不会从这个 JOIN 查询的结果中填充。 因此，每个连接关系还有一个额外的查询，正如即时加载部分所述。</span><br><br><span class="hljs-comment">// 和 with() 一样，你可以 join 多个关联表；你可以动态的自定义 你的关联查询；你可以使用嵌套关联进行 join。你也可以将 with() 和 joinWith() 组合起来使用。例如：</span><br><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">joinWith</span>([<br>    <span class="hljs-string">&#x27;orders&#x27;</span> =&gt; function (<span class="hljs-variable">$query</span>) &#123;<br>        <span class="hljs-variable">$query</span>-&gt;<span class="hljs-title function_ invoke__">andWhere</span>([<span class="hljs-string">&#x27;&gt;&#x27;</span>, <span class="hljs-string">&#x27;subtotal&#x27;</span>, <span class="hljs-number">100</span>]);<br>    &#125;,<br>])-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;country&#x27;</span>)<br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 有时，当连接两个表时，你可能需要在 JOIN 查询的 ON 部分中指定一些额外的条件。 这可以通过调用 yii\db\ActiveQuery::onCondition() 方法来完成，如下所示：</span><br><br><span class="hljs-comment">// SELECT `customer`.* FROM `customer`</span><br><span class="hljs-comment">// LEFT JOIN `order` ON `order`.`customer_id` = `customer`.`id` AND `order`.`status` = 1 </span><br><span class="hljs-comment">// </span><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` IN (...)</span><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">joinWith</span>([<br>    <span class="hljs-string">&#x27;orders&#x27;</span> =&gt; function (<span class="hljs-variable">$query</span>) &#123;<br>        <span class="hljs-variable">$query</span>-&gt;<span class="hljs-title function_ invoke__">onCondition</span>([<span class="hljs-string">&#x27;order.status&#x27;</span> =&gt; <span class="hljs-title class_">Order</span>::<span class="hljs-variable constant_">STATUS_ACTIVE</span>]);<br>    &#125;,<br>])-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 以上查询取出 所有 客户，并为每个客户取回所有活跃订单。 请注意，这与我们之前的例子不同，后者仅取出至少有一个活跃订单的客户。</span><br><br><span class="hljs-comment">// 提示： 当通过 onCondition() 修改 yii\db\ActiveQuery 时， 如果查询涉及到 JOIN 查询，那么条件将被放在 ON 部分。如果查询不涉及 JOIN ，条件将自动附加到查询的 WHERE 部分。 因此，它可以只包含 包含了关联表的列 的条件。（译者注：意思是 onCondition() 中可以只写关联表的列，主表的列写不写都行）</span><br></code></pre></td></tr></table></figure><h2 id="反向关联"><a href="#反向关联" class="headerlink" title="反向关联"></a>反向关联</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 两个 Active Record 类之间的关联声明往往是相互关联的。例如，Customer 是 通过 orders 关联到 Order ，而Order 通过 customer 又关联回到了 Customer。</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCustomer</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasOne</span>(<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-string">&#x27;customer_id&#x27;</span>]);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 现在考虑下面的一段代码：</span><br><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123</span><br><span class="hljs-variable">$order</span> = <span class="hljs-variable">$customer</span>-&gt;orders[<span class="hljs-number">0</span>];<br><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123</span><br><span class="hljs-variable">$customer2</span> = <span class="hljs-variable">$order</span>-&gt;customer;<br><br><span class="hljs-comment">// 显示 &quot;not the same&quot;</span><br><span class="hljs-keyword">echo</span> <span class="hljs-variable">$customer2</span> === <span class="hljs-variable">$customer</span> ? <span class="hljs-string">&#x27;same&#x27;</span> : <span class="hljs-string">&#x27;not the same&#x27;</span>;<br><span class="hljs-comment">// 我们原本认为 $customer 和 $customer2 是一样的，但不是！其实他们确实包含相同的 客户数据，但它们是不同的对象。 访问 $order-&gt;customer 时，需要执行额外的 SQL 语句， 以填充出一个新对象 $customer2。</span><br><br><span class="hljs-comment">// 为了避免上述例子中最后一个 SQL 语句被冗余执行，我们应该告诉 Yii customer 是 orders 的 反向关联，可以通过调用 inverseOf() 方法声明， 如下所示：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>])-&gt;<span class="hljs-title function_ invoke__">inverseOf</span>(<span class="hljs-string">&#x27;customer&#x27;</span>);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 这样修改关联声明后：</span><br><br><span class="hljs-comment">// SELECT * FROM `customer` WHERE `id` = 123</span><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><br><span class="hljs-comment">// SELECT * FROM `order` WHERE `customer_id` = 123</span><br><span class="hljs-variable">$order</span> = <span class="hljs-variable">$customer</span>-&gt;orders[<span class="hljs-number">0</span>];<br><br><span class="hljs-comment">// No SQL will be executed</span><br><span class="hljs-variable">$customer2</span> = <span class="hljs-variable">$order</span>-&gt;customer;<br><br><span class="hljs-comment">// 输出 &quot;same&quot;</span><br><span class="hljs-keyword">echo</span> <span class="hljs-variable">$customer2</span> === <span class="hljs-variable">$customer</span> ? <span class="hljs-string">&#x27;same&#x27;</span> : <span class="hljs-string">&#x27;not the same&#x27;</span>;<br><br><span class="hljs-comment">// 注意： 反向关联不能用在有 连接表 关联声明中。 也就是说，如果一个关联关系通过 via() 或 viaTable() 声明， 你就不能再调用 inverseOf() 了。</span><br></code></pre></td></tr></table></figure><h2 id="保存关联数据"><a href="#保存关联数据" class="headerlink" title="保存关联数据"></a>保存关联数据</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 在使用关联数据时，您经常需要建立不同数据之间的关联或销毁 现有关联。这需要为定义的关联的列设置正确的值。通过使用 Active Record， 你就可以编写如下代码：</span><br><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><span class="hljs-variable">$order</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Order</span>();<br><span class="hljs-variable">$order</span>-&gt;subtotal = <span class="hljs-number">100</span>;<br><span class="hljs-comment">// ...</span><br><br><span class="hljs-comment">// 为 Order 设置属性以定义与 &quot;customer&quot; 的关联关系</span><br><span class="hljs-variable">$order</span>-&gt;customer_id = <span class="hljs-variable">$customer</span>-&gt;id;<br><span class="hljs-variable">$order</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();<br>Active Record 提供了 <span class="hljs-title function_ invoke__">link</span>() 方法，可以更好地完成此任务：<br><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-number">123</span>);<br><span class="hljs-variable">$order</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Order</span>();<br><span class="hljs-variable">$order</span>-&gt;subtotal = <span class="hljs-number">100</span>;<br><span class="hljs-comment">// ...</span><br><br><span class="hljs-variable">$order</span>-&gt;<span class="hljs-title function_ invoke__">link</span>(<span class="hljs-string">&#x27;customer&#x27;</span>, <span class="hljs-variable">$customer</span>);<br><span class="hljs-comment">// link()方法需要指定关联名 和要建立关联的目标 Active Record 实例。该方法将修改属性的值 以连接两个 Active Record 实例，并将其保存到数据库。在上面的例子中，它将设置 Order 实例的 customer_id 属性 为 Customer 实例的 id 属性的值，然后保存 到数据库。</span><br><br><span class="hljs-comment">// 注意： 你不能关联两个新的 Active Record 实例。</span><br><span class="hljs-comment">// 使用 link() 的好处在通过 junction table 定义关系时更加明显。 例如，你可以使用以下代码关联 Order 实例 和 Item 实例：</span><br><br><span class="hljs-variable">$order</span>-&gt;<span class="hljs-title function_ invoke__">link</span>(<span class="hljs-string">&#x27;items&#x27;</span>, <span class="hljs-variable">$item</span>);<br><span class="hljs-comment">// 上述代码会自动在 order_item 关联表中插入一行，以关联 order 和 item 这两个数据记录。</span><br><br><span class="hljs-comment">// 信息： link() 方法在保存相应的 Active Record 实例时， 将不会执行任何数据验证。在调用此方法之前， 您应当验证所有的输入数据。</span><br><br><span class="hljs-comment">//link() 方法的反向操作是 unlink() 方法， 这将可以断掉两个 Active Record 实例间的已经存在了的关联关系。例如，</span><br><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;orders&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">where</span>([<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-number">123</span>])-&gt;<span class="hljs-title function_ invoke__">one</span>();<br><span class="hljs-variable">$customer</span>-&gt;<span class="hljs-title function_ invoke__">unlink</span>(<span class="hljs-string">&#x27;orders&#x27;</span>, <span class="hljs-variable">$customer</span>-&gt;orders[<span class="hljs-number">0</span>]);<br><span class="hljs-comment">// 默认情况下，unlink() 方法将设置指定的外键值， 以把现有的关联指定为 null。此外，你可以选择通过将 $delete 参数设置为true 传递给方法， 删除包含此外键值的表记录行。</span><br><br><span class="hljs-comment">// 当关联关系中有连接表时，调用 unlink() 时， 如果 $delete 参数是 true 的话，将导致 连接表中的外键或相应的行被删除。</span><br></code></pre></td></tr></table></figure><h2 id="跨数据库关联"><a href="#跨数据库关联" class="headerlink" title="跨数据库关联"></a>跨数据库关联</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// Active Record 允许您在不同数据库驱动的 Active Record 类之间声明关联关系。 这些数据库可以是不同的类型（例如 MySQL 和 PostgreSQL ，或是 MS SQL 和 MongoDB），它们也可以运行在 不同的服务器上。你可以使用相同的语法来执行关联查询。例如，</span><br><br><span class="hljs-comment">// Customer 对应的表是关系数据库中（比如 MySQL）的 &quot;customer&quot; 表</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tableName</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;customer&#x27;</span>;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getComments</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-comment">// 一个 customer 有很多条评论（comments）</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Comment</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// Comment 对应的是 MongoDB 数据库中的  &quot;comment&quot; 集合（译者注：MongoDB 中的集合相当于 MySQL 中的表）</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Comment</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">mongodb</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">collectionName</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;comment&#x27;</span>;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCustomer</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-comment">// 一条评论对应一位 customer</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasOne</span>(<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;id&#x27;</span> =&gt; <span class="hljs-string">&#x27;customer_id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;comments&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 本节中描述的大多数关联查询功能，你都可以抄一抄。</span><br><br><span class="hljs-comment">// 注意： joinWith() 这个功能限制于某些数据库是否支持跨数据库 JOIN 查询。  因此，你再上述的代码里就不能用此方法了，因为 MongoDB 不支持 JOIN 查询。</span><br></code></pre></td></tr></table></figure><h2 id="自定义查询类"><a href="#自定义查询类" class="headerlink" title="自定义查询类"></a>自定义查询类</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 默认情况下，yii\db\ActiveQuery 支持所有 Active Record 查询。要在 Active Record 类中使用自定义的查询类， 您应该重写 yii\db\ActiveRecord::find() 方法并返回一个你自定义查询类的实例。 例如，</span><br><br><span class="hljs-comment">// file Comment.php</span><br><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">app</span>\<span class="hljs-title class_">models</span>;<br><br><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span>;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Comment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">CommentQuery</span>(<span class="hljs-title function_ invoke__">get_called_class</span>());<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 现在，对于 Comment 类，不管你执行查询（比如 find()、findOne()），还是定义一个关联（比如 hasOne()）， 你都将调用到 CommentQuery 实例，而不再是 ActiveQuery 实例。</span><br><br><span class="hljs-comment">// 现在你可以定义 CommentQuery 类了，发挥你的奇技淫巧，以改善查询构建体验。例如，</span><br><br><span class="hljs-comment">// file CommentQuery.php</span><br><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">app</span>\<span class="hljs-title class_">models</span>;<br><br><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveQuery</span>;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CommentQuery</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveQuery</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">// 默认加上一些条件（可以跳过）</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">andOnCondition</span>([<span class="hljs-string">&#x27;deleted&#x27;</span> =&gt; <span class="hljs-literal">false</span>]);<br>        <span class="hljs-built_in">parent</span>::<span class="hljs-title function_ invoke__">init</span>();<br>    &#125;<br><br>    <span class="hljs-comment">// ... 在这里加上自定义的查询方法 ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">active</span>(<span class="hljs-params"><span class="hljs-variable">$state</span> = <span class="hljs-literal">true</span></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">andOnCondition</span>([<span class="hljs-string">&#x27;active&#x27;</span> =&gt; <span class="hljs-variable">$state</span>]);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 注意： 作为 onCondition() 方法的替代方案，你应当调用 andOnCondition() 或 orOnCondition() 方法来附加新增的条件， 不然在一个新定义的查询方法，已存在的条件可能会被覆盖。</span><br><br><span class="hljs-comment">// 然后你就可以先下面这样构建你的查询了：</span><br><br><span class="hljs-variable">$comments</span> = <span class="hljs-title class_">Comment</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">active</span>()-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-variable">$inactiveComments</span> = <span class="hljs-title class_">Comment</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">active</span>(<span class="hljs-literal">false</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 提示： 在大型项目中，建议您使用自定义查询类来容纳大多数与查询相关的代码， 以使 Active Record 类保持简洁。</span><br><br><span class="hljs-comment">// 您还可以在 Comment 关联关系的定义中或在执行关联查询时，使用刚刚新建查询构建方法：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getActiveComments</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Comment</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>])-&gt;<span class="hljs-title function_ invoke__">active</span>();<br>    &#125;<br>&#125;<br><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">joinWith</span>(<span class="hljs-string">&#x27;activeComments&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-comment">// 或者这样</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getComments</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Comment</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">joinWith</span>([<br>    <span class="hljs-string">&#x27;comments&#x27;</span> =&gt; function(<span class="hljs-variable">$q</span>) &#123;<br>        <span class="hljs-variable">$q</span>-&gt;<span class="hljs-title function_ invoke__">active</span>();<br>    &#125;<br>])-&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 提示： 在 Yii 1.1 中，有个概念叫做 命名范围。命名范围在 Yii 2.0 中不再支持， 你依然可以使用自定义查询类、查询方法来达到一样的效果。</span><br></code></pre></td></tr></table></figure><h2 id="选择额外的字段"><a href="#选择额外的字段" class="headerlink" title="选择额外的字段"></a>选择额外的字段</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 当 Active Record 实例从查询结果中填充时，从数据结果集中， 其属性的值将被相应的列填充。</span><br><br><span class="hljs-comment">// 你可以从查询中获取其他列或值，并将其存储在 Active Record 活动记录中。 例如，假设我们有一个名为 room 的表，其中包含有关酒店可用房间的信息。 每个房间使用字段 length，width，height 存储有关其空间大小的信息。 想象一下，我们需要检索出所有可用房间的列表，并按照体积大小倒序排列。 你不可能使用 PHP 来计算体积，但是，由于我们需要按照它的值对这些记录进行排序，你依然需要 volume （体积） 来显示在这个列表中。 为了达到这个目标，你需要在你的 Room 活动记录类中声明一个额外的字段，它将存储 volume 的值：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Room</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-variable">$volume</span>;<br><br>    <span class="hljs-comment">// ...</span><br>&#125;<br><span class="hljs-comment">// 然后，你需要撰写一个查询，它可以计算房间的大小并执行排序：</span><br><br><span class="hljs-variable">$rooms</span> = <span class="hljs-title class_">Room</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">select</span>([<br>        <span class="hljs-string">&#x27;&#123;&#123;room&#125;&#125;.*&#x27;</span>, // select all columns<br>        <span class="hljs-string">&#x27;([[length]] * [[width]] * [[height]]) AS volume&#x27;</span>, // 计算体积<br>    ])<br>    -&gt;<span class="hljs-title function_ invoke__">orderBy</span>(<span class="hljs-string">&#x27;volume DESC&#x27;</span>) <span class="hljs-comment">// 使用排序</span><br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><br><span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$rooms</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$room</span>) &#123;<br>    <span class="hljs-keyword">echo</span> <span class="hljs-variable">$room</span>-&gt;volume; <span class="hljs-comment">// 包含了由 SQL 计算出的值</span><br>&#125;<br><span class="hljs-comment">// 额外字段的特性对于聚合查询非常有用。 假设您需要显示一系列客户的订单数量。 首先，您需要使用 orders 关系声明一个 Customer 类，并指定额外字段来存储 count 结果：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-variable">$ordersCount</span>;<br><br>    <span class="hljs-comment">// ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 然后你可以编写一个查询来 JOIN 订单表，并计算订单的总数：</span><br><br><span class="hljs-variable">$customers</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()<br>    -&gt;<span class="hljs-title function_ invoke__">select</span>([<br>        <span class="hljs-string">&#x27;&#123;&#123;customer&#125;&#125;.*&#x27;</span>, // select customer 表所有的字段<br>        <span class="hljs-string">&#x27;COUNT(&#123;&#123;order&#125;&#125;.id) AS ordersCount&#x27;</span> // 计算订单总数<br>    ])<br>    -&gt;<span class="hljs-title function_ invoke__">joinWith</span>(<span class="hljs-string">&#x27;orders&#x27;</span>) <span class="hljs-comment">// 连接表</span><br>    -&gt;<span class="hljs-title function_ invoke__">groupBy</span>(<span class="hljs-string">&#x27;&#123;&#123;customer&#125;&#125;.id&#x27;</span>) <span class="hljs-comment">// 分组查询，以确保聚合函数生效</span><br>    -&gt;<span class="hljs-title function_ invoke__">all</span>();<br><span class="hljs-comment">// 使用此方法的一个缺点是，如果数据不是从 SQL 查询上加载的，它必须再单独计算一遍。 因此，如果你通过常规查询获取个别的数据记录时，它没有额外的 select 语句，那么它 将无法返回额外字段的实际值。新保存的记录一样会发生这种情。</span><br><br><span class="hljs-variable">$room</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Room</span>();<br><span class="hljs-variable">$room</span>-&gt;length = <span class="hljs-number">100</span>;<br><span class="hljs-variable">$room</span>-&gt;width = <span class="hljs-number">50</span>;<br><span class="hljs-variable">$room</span>-&gt;height = <span class="hljs-number">2</span>;<br><br><span class="hljs-variable">$room</span>-&gt;volume; <span class="hljs-comment">// 为 `null`, 因为它没有被声明（赋值）</span><br><span class="hljs-comment">// 通过 __get() 和 __set() 魔术方法 我们可以将属性赋予行为特性：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Room</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-variable">$_volume</span>;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setVolume</span>(<span class="hljs-params"><span class="hljs-variable">$volume</span></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable language_">$this</span>-&gt;_volume = (<span class="hljs-keyword">float</span>) <span class="hljs-variable">$volume</span>;<br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getVolume</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>(<span class="hljs-variable language_">$this</span>-&gt;length) || <span class="hljs-keyword">empty</span>(<span class="hljs-variable language_">$this</span>-&gt;width) || <span class="hljs-keyword">empty</span>(<span class="hljs-variable language_">$this</span>-&gt;height)) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>        <br>        <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">$this</span>-&gt;_volume === <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">setVolume</span>(<br>                <span class="hljs-variable">$this</span>-&gt;length * <span class="hljs-variable">$this</span>-&gt;width * <span class="hljs-variable">$this</span>-&gt;height<br>            );<br>        &#125;<br>        <br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;_volume;<br>    &#125;<br><br>    <span class="hljs-comment">// ...</span><br>&#125;<br><span class="hljs-comment">// 当 select 查询不提供 volume 体积时，这模型将能够自动计算体积的值出来， 当访问模型的属性的时候。</span><br><br><span class="hljs-comment">// 当定义关联关系的时候，你也可以计算聚合字段：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-variable">$_ordersCount</span>;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setOrdersCount</span>(<span class="hljs-params"><span class="hljs-variable">$count</span></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable language_">$this</span>-&gt;_ordersCount = (<span class="hljs-keyword">int</span>) <span class="hljs-variable">$count</span>;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrdersCount</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">$this</span>-&gt;isNewRecord) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>; <span class="hljs-comment">// 这样可以避免调用空主键进行查询</span><br>        &#125;<br><br>        <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">$this</span>-&gt;_ordersCount === <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">setOrdersCount</span>(<span class="hljs-variable">$this</span>-&gt;<span class="hljs-title function_ invoke__">getOrders</span>()-&gt;<span class="hljs-title function_ invoke__">count</span>()); <span class="hljs-comment">// 根据关联关系按需计算聚合字段</span><br>        &#125;<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;_ordersCount;<br>    &#125;<br><br>    <span class="hljs-comment">// ...</span><br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 使用此代码，如果 &#x27;select&#x27; 语句中存在 &#x27;ordersCount&#x27; - 它会从查询结果集获取数据填充 Customer::ordersCount 属性， 否则它会在被访问的时候，使用 Customer::orders 关联按需计算。</span><br><br><span class="hljs-comment">// 这种方法也适用于创建一些关联数据的快捷访问方式，特别是对于聚合。 例如：</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 为聚合数据定义一个只读的虚拟属性</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrdersCount</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">$this</span>-&gt;isNewRecord) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>; <span class="hljs-comment">//  这样可以避免调用空主键进行查询</span><br>        &#125;<br>        <br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">empty</span>(<span class="hljs-variable language_">$this</span>-&gt;ordersAggregation) ? <span class="hljs-number">0</span> : <span class="hljs-variable language_">$this</span>-&gt;ordersAggregation[<span class="hljs-number">0</span>][<span class="hljs-string">&#x27;counted&#x27;</span>];<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 声明一个常规的 &#x27;orders&#x27; 关联</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">hasMany</span>(<span class="hljs-title class_">Order</span>::<span class="hljs-title function_ invoke__">className</span>(), [<span class="hljs-string">&#x27;customer_id&#x27;</span> =&gt; <span class="hljs-string">&#x27;id&#x27;</span>]);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 基于 &#x27;orders&#x27; 关联，声明一个用于查询聚合的新关联</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrdersAggregation</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">getOrders</span>()<br>            -&gt;<span class="hljs-title function_ invoke__">select</span>([<span class="hljs-string">&#x27;customer_id&#x27;</span>, <span class="hljs-string">&#x27;counted&#x27;</span> =&gt; <span class="hljs-string">&#x27;count(*)&#x27;</span>])<br>            -&gt;<span class="hljs-title function_ invoke__">groupBy</span>(<span class="hljs-string">&#x27;customer_id&#x27;</span>)<br>            -&gt;<span class="hljs-title function_ invoke__">asArray</span>(<span class="hljs-literal">true</span>);<br>    &#125;<br><br>    <span class="hljs-comment">// ...</span><br>&#125;<br><br><span class="hljs-keyword">foreach</span> (<span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">find</span>()-&gt;<span class="hljs-title function_ invoke__">with</span>(<span class="hljs-string">&#x27;ordersAggregation&#x27;</span>)-&gt;<span class="hljs-title function_ invoke__">all</span>() <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) &#123;<br>    <span class="hljs-keyword">echo</span> <span class="hljs-variable">$customer</span>-&gt;ordersCount; <span class="hljs-comment">// 输出关联的聚合数据，而不需要额外的查询，因为我们用了即时加载</span><br>&#125;<br><br><span class="hljs-variable">$customer</span> = <span class="hljs-title class_">Customer</span>::<span class="hljs-title function_ invoke__">findOne</span>(<span class="hljs-variable">$pk</span>);<br><span class="hljs-variable">$customer</span>-&gt;ordersCount; <span class="hljs-comment">// 从延迟加载的关联中，输出聚合数据</span><br></code></pre></td></tr></table></figure><p>————————————————<br>文章来源于Yii官方文档：<a href="https://www.yiiframework.com/doc/guide/2.0/zh-cn/db-active-record">活动记录（Active Record）</a> </p>]]></content>
    
    
    <summary type="html">Yii中活动记录（Active Record）类的使用</summary>
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="PHP" scheme="http://www.loquy.cn/tags/PHP/"/>
    
    <category term="Yii" scheme="http://www.loquy.cn/tags/Yii/"/>
    
  </entry>
  
  <entry>
    <title>PHP 7 新特性</title>
    <link href="http://www.loquy.cn/posts/a8d34c6a.html"/>
    <id>http://www.loquy.cn/posts/a8d34c6a.html</id>
    <published>2020-07-13T14:51:37.000Z</published>
    <updated>2020-07-13T14:51:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="标量类型声明"><a href="#标量类型声明" class="headerlink" title="标量类型声明"></a>标量类型声明</h1><p>标量类型声明 有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数（无论用强制模式还是严格模式）： 字符串 (string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。它们扩充了PHP5中引入的其他类型：类名，接口，数组和 回调类型。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 强制模式</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sumOfInts</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> ...<span class="hljs-variable">$ints</span></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_sum</span>(<span class="hljs-variable">$ints</span>);<br>&#125;<br><br><span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-title function_ invoke__">sumOfInts</span>(<span class="hljs-number">2</span>, <span class="hljs-string">&#x27;3&#x27;</span>, <span class="hljs-number">4.1</span>));<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">int(9)</code></pre><p>要使用严格模式，一个 declare 声明指令必须放在文件的顶部。这意味着严格声明标量是基于文件可配的。 这个指令不仅影响参数的类型声明，也影响到函数的返回值声明]</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 严格模式</span><br><span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sumOfInts</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> ...<span class="hljs-variable">$ints</span></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_sum</span>(<span class="hljs-variable">$ints</span>);<br>&#125;<br><br><span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-title function_ invoke__">sumOfInts</span>(<span class="hljs-number">2</span>, <span class="hljs-string">&#x27;3&#x27;</span>, <span class="hljs-number">4.1</span>));<br></code></pre></td></tr></table></figure><p>以上程序由于采用了严格模式，所以如果参数中出现不适整数的类型会报错，执行输出结果为：</p><pre><code class="hljs">PHP Fatal error:  Uncaught TypeError: Argument 2 passed to sumOfInts() must be of the type integer, string given...</code></pre><h1 id="返回值类型声明"><a href="#返回值类型声明" class="headerlink" title="返回值类型声明"></a>返回值类型声明</h1><p>PHP 7 增加了对返回类型声明的支持。 类似于参数类型声明，返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">arraysSum</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> ...<span class="hljs-variable">$arrays</span></span>): <span class="hljs-title">array</span></span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_map</span>(function(<span class="hljs-keyword">array</span> <span class="hljs-variable">$array</span>): <span class="hljs-keyword">int</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_sum</span>(<span class="hljs-variable">$array</span>);<br>    &#125;, <span class="hljs-variable">$arrays</span>);<br>&#125;<br><br><span class="hljs-title function_ invoke__">print_r</span>(<span class="hljs-title function_ invoke__">arraysSum</span>([<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>], [<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>], [<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>]));<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">Array(    [0] =&gt; 6    [1] =&gt; 15    [2] =&gt; 24)</code></pre><h1 id="null合并运算符"><a href="#null合并运算符" class="headerlink" title="null合并运算符"></a>null合并运算符</h1><p>由于日常使用中存在大量同时使用三元表达式和 isset()的情况， 我们添加了 null 合并运算符 (??) 这个语法糖。如果变量存在且值不为 NULL， 它就会返回自身的值，否则返回它的第二个操作数。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 如果$_GET[&#x27;user&#x27;]存在且不为空则返回它自己，否则返回合并运算符后面的值</span><br><span class="hljs-variable">$username</span> = <span class="hljs-variable">$_GET</span>[<span class="hljs-string">&#x27;user&#x27;</span>] ?? <span class="hljs-string">&#x27;nobody&#x27;</span>;<br><span class="hljs-comment">// 相当于:</span><br><span class="hljs-variable">$username</span> = <span class="hljs-keyword">isset</span>(<span class="hljs-variable">$_GET</span>[<span class="hljs-string">&#x27;user&#x27;</span>]) ? <span class="hljs-variable">$_GET</span>[<span class="hljs-string">&#x27;user&#x27;</span>] : <span class="hljs-string">&#x27;nobody&#x27;</span>;<br><br><span class="hljs-comment">// 多个合并运算符可以一起使用</span><br><span class="hljs-variable">$username</span> = <span class="hljs-variable">$_GET</span>[<span class="hljs-string">&#x27;user&#x27;</span>] ?? <span class="hljs-variable">$_POST</span>[<span class="hljs-string">&#x27;user&#x27;</span>] ?? <span class="hljs-string">&#x27;nobody&#x27;</span>;<br></code></pre></td></tr></table></figure><h1 id="太空船操作符（组合比较符）"><a href="#太空船操作符（组合比较符）" class="headerlink" title="太空船操作符（组合比较符）"></a>太空船操作符（组合比较符）</h1><p>太空船操作符用于比较两个表达式。当 $a 小于、等于或大于 $b 时它分别返回 -1  0 或 1。 比较的原则是沿用 PHP 的常规比较规则进行的。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">// 整数</span><br><span class="hljs-keyword">echo</span> <span class="hljs-number">1</span> &lt;=&gt; <span class="hljs-number">1</span>; <span class="hljs-comment">// 0</span><br><span class="hljs-keyword">echo</span> <span class="hljs-number">1</span> &lt;=&gt; <span class="hljs-number">2</span>; <span class="hljs-comment">// -1</span><br><span class="hljs-keyword">echo</span> <span class="hljs-number">2</span> &lt;=&gt; <span class="hljs-number">1</span>; <span class="hljs-comment">// 1</span><br><br><span class="hljs-comment">// 浮点数</span><br><span class="hljs-keyword">echo</span> <span class="hljs-number">1.5</span> &lt;=&gt; <span class="hljs-number">1.5</span>; <span class="hljs-comment">// 0</span><br><span class="hljs-keyword">echo</span> <span class="hljs-number">1.5</span> &lt;=&gt; <span class="hljs-number">2.5</span>; <span class="hljs-comment">// -1</span><br><span class="hljs-keyword">echo</span> <span class="hljs-number">2.5</span> &lt;=&gt; <span class="hljs-number">1.5</span>; <span class="hljs-comment">// 1</span><br> <br><span class="hljs-comment">// 字符串</span><br><span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;a&quot;</span> &lt;=&gt; <span class="hljs-string">&quot;a&quot;</span>; <span class="hljs-comment">// 0</span><br><span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;a&quot;</span> &lt;=&gt; <span class="hljs-string">&quot;b&quot;</span>; <span class="hljs-comment">// -1</span><br><span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;b&quot;</span> &lt;=&gt; <span class="hljs-string">&quot;a&quot;</span>; <span class="hljs-comment">// 1</span><br></code></pre></td></tr></table></figure><h1 id="通过-define-定义常量数组"><a href="#通过-define-定义常量数组" class="headerlink" title="通过 define() 定义常量数组"></a>通过 define() 定义常量数组</h1><p>Array 类型的常量现在可以通过 define() 来定义。在 PHP5.6 中仅能通过 const 定义。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-title function_ invoke__">define</span>(<span class="hljs-string">&#x27;ANIMALS&#x27;</span>, [<br>    <span class="hljs-string">&#x27;dog&#x27;</span>,<br>    <span class="hljs-string">&#x27;cat&#x27;</span>,<br>    <span class="hljs-string">&#x27;bird&#x27;</span><br>]);<br><br><span class="hljs-keyword">echo</span> ANIMALS[<span class="hljs-number">1</span>]; <span class="hljs-comment">// 输出 &quot;cat&quot;</span><br></code></pre></td></tr></table></figure><h1 id="匿名类"><a href="#匿名类" class="headerlink" title="匿名类"></a>匿名类</h1><p>现在支持通过 new class 来实例化一个匿名类，这可以用来替代一些“用后即焚”的完整类定义。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Logger</span> </span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">log</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-variable">$msg</span></span>)</span>;<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Application</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-variable">$logger</span>;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLogger</span>(<span class="hljs-params"></span>): <span class="hljs-title">Logger</span> </span>&#123;<br>         <span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;logger;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setLogger</span>(<span class="hljs-params">Logger <span class="hljs-variable">$logger</span></span>) </span>&#123;<br>         <span class="hljs-variable language_">$this</span>-&gt;logger = <span class="hljs-variable">$logger</span>;<br>    &#125;<br>&#125;<br><br><span class="hljs-variable">$app</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Application</span>;<br><span class="hljs-variable">$app</span>-&gt;<span class="hljs-title function_ invoke__">setLogger</span>(<span class="hljs-keyword">new</span> <span class="hljs-keyword">class</span> <span class="hljs-keyword">implements</span> Logger &#123;<br>    <span class="hljs-keyword">public</span> function <span class="hljs-title function_ invoke__">log</span>(<span class="hljs-keyword">string</span> <span class="hljs-variable">$msg</span>) &#123;<br>        <span class="hljs-keyword">echo</span> <span class="hljs-variable">$msg</span>;<br>    &#125;<br>&#125;);<br><br><span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-variable">$app</span>-&gt;<span class="hljs-title function_ invoke__">getLogger</span>());<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">object(class@anonymous)#2 (0) &#123;&#125;</code></pre><h1 id="Unicode-codepoint-转译语法"><a href="#Unicode-codepoint-转译语法" class="headerlink" title="Unicode codepoint 转译语法"></a>Unicode codepoint 转译语法</h1><p>这接受一个以16进制形式的 Unicode codepoint，并打印出一个双引号或 heredoc 包围的 UTF-8 编码格式的字符串。 可以接受任何有效的 codepoint，并且开头的 0 是可以省略的。</p><p>echo “\u{aa}”;<br>echo “\u{0000aa}”;<br>echo “\u{9999}”;<br>以上例程会输出：</p><pre><code class="hljs">ªª (same as before but with optional leading 0&#39;s)香</code></pre><h1 id="Closure-call"><a href="#Closure-call" class="headerlink" title="Closure::call()"></a>Closure::call()</h1><p>Closure::call() 现在有着更好的性能，简短干练的暂时绑定一个方法到对象上闭包并调用它。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A</span> </span>&#123;<span class="hljs-keyword">private</span> <span class="hljs-variable">$x</span> = <span class="hljs-number">1</span>;&#125;<br><br><span class="hljs-comment">// PHP 7 之前版本的代码</span><br><span class="hljs-variable">$getXCB</span> = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>&#123;<span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;x;&#125;;<br><span class="hljs-variable">$getX</span> = <span class="hljs-variable">$getXCB</span>-&gt;<span class="hljs-title function_ invoke__">bindTo</span>(<span class="hljs-keyword">new</span> A, <span class="hljs-string">&#x27;A&#x27;</span>); <span class="hljs-comment">// 中间层闭包</span><br><span class="hljs-keyword">echo</span> <span class="hljs-variable">$getX</span>();<br><br><span class="hljs-comment">// PHP 7+ 及更高版本的代码</span><br><span class="hljs-variable">$getX</span> = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>&#123;<span class="hljs-keyword">return</span> <span class="hljs-variable language_">$this</span>-&gt;x;&#125;;<br><span class="hljs-keyword">echo</span> <span class="hljs-variable">$getX</span>-&gt;<span class="hljs-title function_ invoke__">call</span>(<span class="hljs-keyword">new</span> A);<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">11</code></pre><h1 id="为unserialize-提供过滤"><a href="#为unserialize-提供过滤" class="headerlink" title="为unserialize()提供过滤"></a>为unserialize()提供过滤</h1><p>这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs php"><br><span class="hljs-comment">// 将所有的对象都转换为 __PHP_Incomplete_Class 对象</span><br><span class="hljs-variable">$data</span> = <span class="hljs-title function_ invoke__">unserialize</span>(<span class="hljs-variable">$foo</span>, [<span class="hljs-string">&quot;allowed_classes&quot;</span> =&gt; <span class="hljs-literal">false</span>]);<br><br><span class="hljs-comment">// 将除 MyClass 和 MyClass2 之外的所有对象都转换为 __PHP_Incomplete_Class 对象</span><br><span class="hljs-variable">$data</span> = <span class="hljs-title function_ invoke__">unserialize</span>(<span class="hljs-variable">$foo</span>, [<span class="hljs-string">&quot;allowed_classes&quot;</span> =&gt; [<span class="hljs-string">&quot;MyClass&quot;</span>, <span class="hljs-string">&quot;MyClass2&quot;</span>]);<br><br><span class="hljs-comment">// 默认情况下所有的类都是可接受的，等同于省略第二个参数</span><br><span class="hljs-variable">$data</span> = <span class="hljs-title function_ invoke__">unserialize</span>(<span class="hljs-variable">$foo</span>, [<span class="hljs-string">&quot;allowed_classes&quot;</span> =&gt; <span class="hljs-literal">true</span>]);<br></code></pre></td></tr></table></figure><h1 id="IntlChar"><a href="#IntlChar" class="headerlink" title="IntlChar"></a>IntlChar</h1><p>新增加的 IntlChar 类旨在暴露出更多的 ICU 功能。这个类自身定义了许多静态方法用于操作多字符集的 unicode 字符。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-string">&#x27;%x&#x27;</span>, <span class="hljs-title class_">IntlChar</span>::<span class="hljs-variable constant_">CODEPOINT_MAX</span>);<br><span class="hljs-keyword">echo</span> <span class="hljs-title class_">IntlChar</span>::<span class="hljs-title function_ invoke__">charName</span>(<span class="hljs-string">&#x27;@&#x27;</span>);<br><span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-title class_">IntlChar</span>::<span class="hljs-title function_ invoke__">ispunct</span>(<span class="hljs-string">&#x27;!&#x27;</span>));<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">10ffffCOMMERCIAL ATbool(true)</code></pre><p>若要使用此类，请先安装Intl扩展</p><h1 id="预期"><a href="#预期" class="headerlink" title="预期"></a>预期</h1><p>预期是向后兼用并增强之前的 assert() 的方法。 它使得在生产环境中启用断言为零成本，并且提供当断言失败时抛出特定异常的能力。</p><p>老版本的API出于兼容目的将继续被维护，assert()现在是一个语言结构，它允许第一个参数是一个表达式，而不仅仅是一个待计算的 string或一个待测试的boolean。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-title function_ invoke__">ini_set</span>(<span class="hljs-string">&#x27;assert.exception&#x27;</span>, <span class="hljs-number">1</span>);<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AssertionError</span> </span>&#123;&#125;<br><br><span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-literal">false</span>, <span class="hljs-keyword">new</span> <span class="hljs-title class_">CustomError</span>(<span class="hljs-string">&#x27;Some error message&#x27;</span>));<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">Fatal error: Uncaught CustomError: Some error message</code></pre><h1 id="Group-use-declarations"><a href="#Group-use-declarations" class="headerlink" title="Group use declarations"></a>Group use declarations</h1><p>从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs php"><br><span class="hljs-comment">// PHP 7 之前的代码</span><br><span class="hljs-keyword">use</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">ClassA</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">ClassB</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">ClassC</span> <span class="hljs-keyword">as</span> <span class="hljs-title">C</span>;<br><br><span class="hljs-keyword">use</span> <span class="hljs-keyword">function</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">fn_a</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-keyword">function</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">fn_b</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-keyword">function</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">fn_c</span>;<br><br><span class="hljs-keyword">use</span> <span class="hljs-keyword">const</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">ConstA</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-keyword">const</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">ConstB</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-keyword">const</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\<span class="hljs-title">ConstC</span>;<br><br><span class="hljs-comment">// PHP 7+ 及更高版本的代码</span><br><span class="hljs-keyword">use</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\&#123;<span class="hljs-title">ClassA</span>, <span class="hljs-title">ClassB</span>, <span class="hljs-title">ClassC</span> <span class="hljs-keyword">as</span> <span class="hljs-title">C</span>&#125;;<br><span class="hljs-keyword">use</span> <span class="hljs-keyword">function</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\&#123;<span class="hljs-title">fn_a</span>, <span class="hljs-title">fn_b</span>, <span class="hljs-title">fn_c</span>&#125;;<br><span class="hljs-keyword">use</span> <span class="hljs-keyword">const</span> <span class="hljs-title">some</span>\<span class="hljs-title">namespace</span>\&#123;<span class="hljs-title">ConstA</span>, <span class="hljs-title">ConstB</span>, <span class="hljs-title">ConstC</span>&#125;;<br></code></pre></td></tr></table></figure><h1 id="生成器可以返回表达式"><a href="#生成器可以返回表达式" class="headerlink" title="生成器可以返回表达式"></a>生成器可以返回表达式</h1><p>此特性基于 PHP 5.5 版本中引入的生成器特性构建的。 它允许在生成器函数中通过使用 return 语法来返回一个表达式 （但是不允许返回引用值）， 可以通过调用 Generator::getReturn() 方法来获取生成器的返回值， 但是这个方法只能在生成器完成产生工作以后调用一次。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs php"><br><span class="hljs-variable">$gen</span> = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>&#123;<br>    <span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>;<br>    <span class="hljs-keyword">yield</span> <span class="hljs-number">2</span>;<br><br>    <span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;<br>&#125;)();<br><br><span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$gen</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$val</span>) &#123;<br>    <span class="hljs-keyword">echo</span> <span class="hljs-variable">$val</span>, PHP_EOL;<br>&#125;<br><br><span class="hljs-keyword">echo</span> <span class="hljs-variable">$gen</span>-&gt;<span class="hljs-title function_ invoke__">getReturn</span>(), PHP_EOL;<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">123</code></pre><p>在生成器中能够返回最终的值是一个非常便利的特性， 因为它使得调用生成器的客户端代码可以直接得到生成器（或者其他协同计算）的返回值， 相对于之前版本中客户端代码必须先检查生成器是否产生了最终的值然后再进行响应处理 来得方便多了。</p><h1 id="Generator-delegation"><a href="#Generator-delegation" class="headerlink" title="Generator delegation"></a>Generator delegation</h1><p>现在，只需在最外层生成其中使用 yield from， 就可以把一个生成器自动委派给其他的生成器， Traversable 对象或者 array。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs php"><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">gen</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>;<br>    <span class="hljs-keyword">yield</span> <span class="hljs-number">2</span>;<br><br>    <span class="hljs-keyword">yield</span> <span class="hljs-keyword">from</span> <span class="hljs-title function_ invoke__">gen2</span>();<br>&#125;<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">gen2</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-keyword">yield</span> <span class="hljs-number">3</span>;<br>    <span class="hljs-keyword">yield</span> <span class="hljs-number">4</span>;<br>&#125;<br><br><span class="hljs-keyword">foreach</span> (<span class="hljs-title function_ invoke__">gen</span>() <span class="hljs-keyword">as</span> <span class="hljs-variable">$val</span>)<br>&#123;<br>    <span class="hljs-keyword">echo</span> <span class="hljs-variable">$val</span>, PHP_EOL;<br>&#125;<br><br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">1234</code></pre><h1 id="整数除法函数-intdiv"><a href="#整数除法函数-intdiv" class="headerlink" title="整数除法函数 intdiv()"></a>整数除法函数 intdiv()</h1><p>新加的函数 intdiv() 用来进行 整数的除法运算。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs php"><br><span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-title function_ invoke__">intdiv</span>(<span class="hljs-number">10</span>, <span class="hljs-number">3</span>));<br></code></pre></td></tr></table></figure><p>以上例程会输出：</p><pre><code class="hljs">int(3)</code></pre><h1 id="会话选项"><a href="#会话选项" class="headerlink" title="会话选项"></a>会话选项</h1><p>session_start() 可以接受一个 array 作为参数， 用来覆盖 php.ini 文件中设置的 会话配置选项。</p><p>在调用 session_start() 的时候， 传入的选项参数中也支持 session.lazy_write 行为， 默认情况下这个配置项是打开的。它的作用是控制 PHP 只有在会话中的数据发生变化的时候才 写入会话存储文件，如果会话中的数据没有发生改变，那么 PHP 会在读取完会话数据之后， 立即关闭会话存储文件，不做任何修改，可以通过设置 read_and_close 来实现。</p><p>例如，下列代码设置 session.cache_limiter 为 private，并且在读取完毕会话数据之后马上关闭会话存储文件。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-title function_ invoke__">session_start</span>([<br>    <span class="hljs-string">&#x27;cache_limiter&#x27;</span> =&gt; <span class="hljs-string">&#x27;private&#x27;</span>,<br>    <span class="hljs-string">&#x27;read_and_close&#x27;</span> =&gt; <span class="hljs-literal">true</span>,<br>]);<br></code></pre></td></tr></table></figure><h1 id="preg-replace-callback-array"><a href="#preg-replace-callback-array" class="headerlink" title="preg_replace_callback_array()"></a>preg_replace_callback_array()</h1><p>在 PHP 7 之前，当使用 preg_replace_callback() 函数的时候， 由于针对每个正则表达式都要执行回调函数，可能导致过多的分支代码。 而使用新加的 preg_replace_callback_array() 函数， 可以使得代码更加简洁。</p><p>现在，可以使用一个关联数组来对每个正则表达式注册回调函数， 正则表达式本身作为关联数组的键， 而对应的回调函数就是关联数组的值。</p><h1 id="CSPRNG-Functions"><a href="#CSPRNG-Functions" class="headerlink" title="CSPRNG Functions"></a>CSPRNG Functions</h1><p>新加入两个跨平台的函数： random_bytes() 和 random_int() 用来产生高安全级别的随机字符串和随机整数。</p><h1 id="可以使用-list-函数来展开实现了-ArrayAccess-接口的对象"><a href="#可以使用-list-函数来展开实现了-ArrayAccess-接口的对象" class="headerlink" title="可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象"></a>可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象</h1><p>在之前版本中，list() 函数不能保证 正确的展开实现了 ArrayAccess 接口的对象， 现在这个问题已经被修复。</p><h1 id="其他特性"><a href="#其他特性" class="headerlink" title="其他特性"></a>其他特性</h1><p>允许在克隆表达式上访问对象成员，例如： (clone $foo)-&gt;bar()。</p><p>————————————————<br>文章来源于PHP官方文档：<a href="https://www.php.net/manual/zh/migration70.new-features.php">PHP 5.6.x 移植到 PHP 7.0.x</a> </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;标量类型声明&quot;&gt;&lt;a href=&quot;#标量类型声明&quot; class=&quot;headerlink&quot; title=&quot;标量类型声明&quot;&gt;&lt;/a&gt;标量类型声明&lt;/h1&gt;&lt;p&gt;标量类型声明 有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数（无论用强制模式还是严格</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="PHP" scheme="http://www.loquy.cn/tags/PHP/"/>
    
  </entry>
  
  <entry>
    <title>安装 LNMP 环境</title>
    <link href="http://www.loquy.cn/posts/5ca3d0c3.html"/>
    <id>http://www.loquy.cn/posts/5ca3d0c3.html</id>
    <published>2020-07-05T03:37:09.000Z</published>
    <updated>2020-07-05T03:37:09.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><ul><li><p>虚拟机中安装 centos 8（自行搜索,安装后只有命令行，图形界面需要另外安装）</p></li><li><p>切换 root 账号</p><pre><code class="hljs">  su root</code></pre></li><li><p>使用 <code>dhclient</code> 命令为 centos 8 分配一个 ip 地址</p></li></ul><p><img src="https://www.loquy.cn/images/1593925975.jpg"></p><ul><li><p>使用vim编辑网卡配置，将上面分配所得的ip地址写入配置文件</p><pre><code class="hljs">  vim /etc/sysconfig/network-scripts/ifcfg-enp0s3</code></pre></li><li><p>注意红框的修改的配置按 <code>i</code> 键插入编辑</p></li></ul><p><img src="https://www.loquy.cn/images/1593924179.jpg"></p><ul><li>按 <code>Esc</code> 键然后 <code>:wq</code> 保存退出</li><li>重启网卡使用 <code>nmcli c reload</code> 命令，ping 下百度发现网络可以用了</li></ul><p><img src="https://www.loquy.cn/images/1593925621.jpg"></p><ul><li><p>使用 dnf 取代了 yum 来进行包管理，安装 nginx、php、mysql</p><pre><code class="hljs">  dnf install nginx php mariadb-server php-mysqlnd</code></pre></li><li><p>把 nginx、php-fpm、mariadb 加入到开机启动</p><pre><code class="hljs">  systemctl enable nginx  systemctl enable php-fpm  systemctl enable mariadb</code></pre></li><li><p>启动 nginx、php-fpm、mariadb</p><pre><code class="hljs">  systemctl start nginx  systemctl start php-fpm  systemctl start mariadb</code></pre></li><li><p>设置防火墙开放 tcp 80 和 tcp 3306 端口</p><pre><code class="hljs">  firewall-cmd --zone=public --add-port=80/tcp --permanent  firewall-cmd --zone=public --add-port=3306/tcp --permanent  firewall-cmd --reload</code></pre></li></ul><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><h2 id="nginx"><a href="#nginx" class="headerlink" title="nginx"></a>nginx</h2><ul><li>浏览器访问服务器 ip</li></ul><p><img src="https://www.loquy.cn/images/1593924883.jpg"></p><h2 id="mysql"><a href="#mysql" class="headerlink" title="mysql"></a>mysql</h2><ul><li><p>设置 mysql 数据库 root 账号密码</p><pre><code class="hljs">  mysqladmin -uroot  password  &#39;your password&#39;</code></pre></li><li><p>root 账号登陆 mysql</p><pre><code class="hljs">  mysql -uroot -p</code></pre></li><li><p>创建一个新用户 web，密码为 123456，授权远程计算机使用账号 web 登陆数据库，并立刻刷新权限  </p><pre><code class="hljs">  MariaDB[(none)]&gt;grant all on *.* to &#39;web&#39;@&#39;%&#39;  identified by &#39;123456&#39;;  MariaDB[(none)]&gt;flush privileges;</code></pre></li><li><p>退出 mysql 数据库</p><pre><code class="hljs">  MariaDB[(none)]&gt; quit;</code></pre></li></ul><p><img src="https://www.loquy.cn/images/1593925030.jpg">    </p><h2 id="php"><a href="#php" class="headerlink" title="php"></a>php</h2><ul><li><p>创建文件 index.php</p><pre><code class="hljs">  touch /usr/share/nginx/html/index.php  echo  &quot;&lt;?php  phpinfo();  ?&gt;&quot; &gt; /usr/share/nginx/html/index.php</code></pre></li><li><p>重启 nginx 服务，使用浏览器访问服务器 ip</p><pre><code class="hljs">  systemctl restart  nginx</code></pre></li></ul><p><img src="https://www.loquy.cn/images/1593924755.jpg">        </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;安装&quot;&gt;&lt;a href=&quot;#安装&quot; class=&quot;headerlink&quot; title=&quot;安装&quot;&gt;&lt;/a&gt;安装&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;虚拟机中安装 centos 8（自行搜索,安装后只有命令行，图形界面需要另外安装）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;切换</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Linux" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Linux/"/>
    
    
    <category term="Linux" scheme="http://www.loquy.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>PHP 面试问题整理</title>
    <link href="http://www.loquy.cn/posts/babcce42.html"/>
    <id>http://www.loquy.cn/posts/babcce42.html</id>
    <published>2020-06-25T02:05:23.000Z</published>
    <updated>2020-07-05T06:07:19.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="PHP-的生命周期是什么？"><a href="#PHP-的生命周期是什么？" class="headerlink" title="PHP 的生命周期是什么？"></a>PHP 的生命周期是什么？</h1><p>PHP 生命周期有5个阶段：</p><ul><li><strong>模块初始化阶段</strong> （module init） <ul><li>Zend 引擎的初始化操作。SAPI、FPM（master 进程 ）启动，加载扩展、模块初始化</li></ul></li><li><strong>请求初始化阶段</strong> （request init） <ul><li>FPM 里 worker 进程接收一个请求并读取请求数据，PHP初始化本次请求所需的环境变量</li></ul></li><li><strong>PHP脚本执行阶段</strong><ul><li>Zend 引擎接将 PHP 代码编译成 opcodes 并顺次执行</li></ul></li><li><strong>请求关闭阶段</strong> （request shutdown） <ul><li>按顺序调用各个模块的 RSHUTDOWN 方法，对每个变量调用 unset 函数</li></ul></li><li><strong>模块关闭阶段</strong> （module shutdown） <ul><li>SAPI 关闭，进行资源的清理，关闭各个模块，关闭 FPM</li></ul></li></ul><h1 id="数据库事务的理解-？"><a href="#数据库事务的理解-？" class="headerlink" title="数据库事务的理解 ？"></a>数据库事务的理解 ？</h1><p> <a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93/103728">数据库</a>事务(transaction)是访问并可能操作各种<a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E9%A1%B9/3227309">数据项</a>的一个数据库操作序列，这些操作要么全部执行,要么全部不执行，是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。 </p><ul><li>原子性（Atomic）<ul><li>事务<code>要么全部完成，要么全部取消</code>。 如果事务崩溃，状态回到事务之前（事务回滚）。</li></ul></li><li>一致性（Consitency）<ul><li>只有合法的数据（依照关系约束和函数约束）才能写入数据库。</li></ul></li><li>隔离性（Isolation）<ul><li>如果2个事务 T1 和 T2 同时运行，事务 T1 和 T2 最终的结果是相同的，不管 T1和T2谁先结束。</li></ul></li><li>持久性（Durability）<ul><li>一旦事务提交，不管发生什么（崩溃或者出错），数据要保存在数据库中。</li></ul></li></ul><h1 id="数据库设计范式是什么-？"><a href="#数据库设计范式是什么-？" class="headerlink" title="数据库设计范式是什么 ？"></a>数据库设计范式是什么 ？</h1><ul><li><p>第一范式（1NF）</p><ul><li>表中的列只能含有原子性(不可再分)的值。</li></ul></li><li><p>第二范式（2NF）</p><ul><li>满足第一范式 ，没有部分依赖</li></ul></li><li><p>第三范式（3NF）</p><ul><li>满足第二范式，没有传递依赖</li></ul></li></ul><h1 id="PHP-Swoole是什么？"><a href="#PHP-Swoole是什么？" class="headerlink" title="PHP Swoole是什么？"></a>PHP Swoole是什么？</h1><ul><li><p>PHP 协程框架</p><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm"><span class="hljs-keyword">Swoole </span>使 PHP 开发人员可以编写高性能高并发的 TCP、UDP、Unix Socket、HTTP、 WebSocket 等服务，让 PHP 不再局限于 Web 领域。<span class="hljs-keyword">Swoole4 </span>协程的成熟将 PHP 带入了前所未有的时期， 为性能的提升提供了独一无二的可能性。<span class="hljs-keyword">Swoole </span>可以广泛应用于互联网、移动通信、云计算、 网络游戏、物联网（IOT）、车联网、智能家居等领域。使用 PHP + <span class="hljs-keyword">Swoole </span>可以使企业 IT 研发团队的效率大大提升，更加专注于开发创新产品 <br></code></pre></td></tr></table></figure></li></ul><h1 id="PHP-和-Nginx-怎么交互的？"><a href="#PHP-和-Nginx-怎么交互的？" class="headerlink" title="PHP 和 Nginx 怎么交互的？"></a>PHP 和 Nginx 怎么交互的？</h1><p>Nginx + PHP 的工程模式下，两位主角分工明确，Nginx 负责承载 HTTP 请求的响应与返回，以及超时控制记录日志等 HTTP 相关的功能，而PHP则负责处理具体请求要做的业务逻辑，它们俩的这种合作模式也是常见的分层架构设计中的一种，在它们各有专注面的同时，FastCGI 又很好的将两块衔接，保障上下游通信交互</p><ul><li>发送 HTTP 请求 Nginx 接收</li><li>Nginx 解析到对应 PHP 文件</li><li>加载 Nginx 的 FastCGI 模块启动对应端口</li><li>PHP-FPM 监听对应端口，接收请求，启用 worker 进程处理</li><li>PHP-FPM 处理完请求，返回给 Nginx</li></ul><h1 id="MySQL-存储引擎有什么？"><a href="#MySQL-存储引擎有什么？" class="headerlink" title="MySQL 存储引擎有什么？"></a><strong>MySQL</strong> 存储引擎有什么？</h1><p> 存储引擎其实就是对于数据库文件的一种存取机制  ，如何实现存储数据，如何为存储的数据建立索引以及   如何更新，查询数据等技术实现的方法。 </p><ul><li><strong>InnoDB</strong> <ul><li>优点支持事务处理、崩溃修复能力和并发控制。缺点是读写效率较差，占用空间大。</li></ul></li><li><strong>MyISAM</strong> <ul><li>优点占用空间小，处理速度快。缺点是不支持事务的完整性和并发性。</li></ul></li><li><strong>MEMORY</strong><ul><li>所有的数据存储在内存中，关闭机器数据消失。</li></ul></li><li><strong>ARCHIVE</strong><ul><li>提供了压缩功能，拥有高效的插入速度，不支持索引，所查询性能较差</li></ul></li></ul><h1 id="PHP-网页跳转的方式？"><a href="#PHP-网页跳转的方式？" class="headerlink" title="PHP 网页跳转的方式？"></a>PHP 网页跳转的方式？</h1><ul><li><p>header()函数;</p> <figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-title function_ invoke__">header</span>(<span class="hljs-string">&#x27;location:http://www.baidu.com&#x27;</span>);<br></code></pre></td></tr></table></figure></li><li><p>meta标签</p> <figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-keyword">echo</span> <span class="hljs-string">&#x27;&lt;meta http-equiv=&quot;refresh&quot; content=&quot;1;url=http://www.baidu.com&quot;&gt;&#x27;</span>;<br></code></pre></td></tr></table></figure></li><li><p>script标签;</p> <figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-keyword">echo</span><span class="hljs-string">&#x27;&lt;script&gt;window.location.href=&quot;http://www.baidu.com&quot;&lt;/script&gt;&#x27;</span>;<br></code></pre></td></tr></table></figure></li></ul><h1 id="Redis-有几种类型"><a href="#Redis-有几种类型" class="headerlink" title="Redis 有几种类型?"></a>Redis 有几种类型?</h1><ul><li><strong>String（字符串）</strong> <ul><li>一个 key 对应一个 value。 </li><li>一个 key 最大能存储 512MB</li><li>常用命令：set、get、decr、incr、mget</li></ul></li><li><strong>Hash（哈希）</strong> <ul><li>键值(key &#x3D;&gt; value)对集合，是一个 string 类型的 field 和 value 的映射表， 特别适合用于存储对象</li><li>每个 hash 可以存储 2<sup>32</sup>  - 1 键值对（40多亿）</li><li>常用命令：hget、hset、hgetall</li></ul></li><li><strong>List（列表）</strong> <ul><li>字符串列表，按照插入顺序排序。可以添加一个元素到列表的头部（左边）  或者尾部（右边）</li><li>列表最多可以包含 2<sup>32</sup>  - 1 个元素 (40多亿)</li><li>list 类型经常会被用于消息队列的服务，以完成多程序之间的消息交换</li><li>常用命令：lpush、rpush、lpop、rpop、lrange</li></ul></li><li><strong>Set（集合）</strong> <ul><li>Set 是 String 类型的无序集合。集合成员是唯一的，这就意味着集合中不能出现重复的数据</li><li>集合中最大的成员数为 2<sup>32</sup> - 1 (40多亿)</li><li>常用命令：sadd、spop、smembers、sunion</li></ul></li><li><strong>Sorted Set（有序集合)</strong> <ul><li>有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员</li><li>不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序</li><li>有序集合的成员是唯一的,但分数(score)却可以重复  </li><li>集合中最大的成员数为 2<sup>32</sup> - 1 (40多亿)</li><li>常用命令：zadd、zrange、zrem、zcard</li></ul></li></ul><h1 id="PHP-数组在底层怎么实现的？"><a href="#PHP-数组在底层怎么实现的？" class="headerlink" title="PHP 数组在底层怎么实现的？"></a>PHP 数组在底层怎么实现的？</h1><p> HashTable 是 zend 的核心数据结构，在PHP里面几乎并用来实现所有常见功能，我们知道的 PHP 数组即是其典型应用，此外，在 zend 内部，如函数符号表、全局变量等也都是基于 hash table 来实现 </p><ul><li>散列表（hashTable）具有如下特点 <ul><li>支持典型的 key &#x3D;&gt; value 查询</li><li>可以当做数组使用</li><li>添加、删除节点是 O(1)复杂度</li><li>key 支持混合类型：同时存在关联数组合索引数组</li><li>Value 支持混合类型：array(“string”,2332)</li><li>支持线性遍历：如 foreach</li></ul></li></ul><h1 id="微信授权登录的流程？"><a href="#微信授权登录的流程？" class="headerlink" title="微信授权登录的流程？"></a>微信授权登录的流程？</h1><ul><li><p>调用 <a href="https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html">wx.login()</a> 获取 <strong>临时登录凭证code</strong> ，并回传到开发者服务器。</p></li><li><p>调用 <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html">auth.code2Session</a> 接口，换取 <strong>用户唯一标识 OpenID</strong> 和 <strong>会话密钥 session_key</strong>。</p></li><li><p>具体思路如下</p><ul><li>在 main.js 中封装公共函数，用于判断用户是否登录</li><li>在 main.js 中分定义全局变量，用于存储接口地址</li><li>如果没有登录、则跳转至登录页面</li><li>进入登录页面</li><li>通过 wx.login 获取用户的 code</li><li>通过 code 获取用户的 SessionKey、OpenId 等信息</li><li>通过 openId 调用后台 Api 获取用户的信息</li><li>获取成功，则说明已经授权过了,直接登录成功</li><li>获取失败，则说明没有授权过，需要授权之后才能进行登录</li><li>用户点击页面微信登录按钮 open-type&#x3D;”getUserInfo”</li><li>获取用户数据，然后调用后台接口写入数据库</li></ul></li></ul><h1 id="什么是消息队列-Message-Queue-？"><a href="#什么是消息队列-Message-Queue-？" class="headerlink" title="什么是消息队列 (Message Queue) ？"></a>什么是消息队列 (Message Queue) ？</h1><ul><li><p>从本质上说消息对列就是一个队列结构的中间件，也就是说消息放入这个中间件之后就可以直接返回，并不需要系统立即处理，而另外会有一个程序读取这些数据，并按顺序进行逐次处理。</p></li><li><p>它有三个好处</p><ul><li><p><strong>异步</strong></p><ul><li>用户注册后，需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式；2.并行方式</li><li>串行方式：将注册信息写入数据库成功后，发送注册邮件，再发送注册短信。以上三个任务全部完成后，返回给客户端</li><li>并行方式：将注册信息写入数据库成功后，发送注册邮件的同时，发送注册短信。以上三个任务完成后，返回给客户端。</li><li>消息队列：将注册信息写入数据库成功后，写入消息队列，异步读取需要发送的邮件和短信</li></ul></li><li><p><strong>解耦</strong></p><ul><li>订单系统：用户下单后，订单系统完成持久化处理，将消息写入消息队列，返回用户订单下单成功</li><li>库存系统：订阅下单的消息，采用拉&#x2F;推的方式，获取下单信息，库存系统根据下单信息，进行库存操作</li><li>假如：在下单时库存系统不能正常使用。也不影响正常下单，因为下单后，订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦</li></ul></li><li><p><strong>削峰&#x2F;限流</strong></p><ul><li>秒杀活动，一般会因为流量过大，导致流量暴增，应用挂掉。为解决这个问题，一般需要在应用前端加入消息队列</li><li>可以控制活动的人数，缓解短时间内高流量压垮应用  </li><li>用户的请求，服务器接收后，首先写入消息队列。假如消息队列长度超过最大数量，则直接抛弃用户请求或跳转到错误页面 </li><li>秒杀业务根据消息队列中的请求信息，再做后续处理</li></ul></li></ul></li><li><p>使用PHP的数组函数 <strong>array_push、array_shift</strong> 实现一个队列</p></li></ul><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">QueueArray</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-variable">$arr</span> = <span class="hljs-keyword">array</span>();<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tailEnqueue</span>(<span class="hljs-params"><span class="hljs-variable">$val</span></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_push</span>(<span class="hljs-variable">$this</span>-&gt;arr, <span class="hljs-variable">$val</span>); <span class="hljs-comment">// 队尾入队</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tailDequeue</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_pop</span>(<span class="hljs-variable">$this</span>-&gt;arr); <span class="hljs-comment">// 队尾出队</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">headEnqueue</span>(<span class="hljs-params"><span class="hljs-variable">$val</span></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_unshift</span>(<span class="hljs-variable">$this</span>-&gt;arr, <span class="hljs-variable">$val</span>); <span class="hljs-comment">// 队首入队</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">headDequeue</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">array_shift</span>(<span class="hljs-variable">$this</span>-&gt;arr); <span class="hljs-comment">//队首出队</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">length</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">count</span>(<span class="hljs-variable">$this</span>-&gt;arr); <span class="hljs-comment">// 队列长度</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">head</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">reset</span>(<span class="hljs-variable">$this</span>-&gt;arr); <span class="hljs-comment">// 获取队首元素</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tail</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">end</span>(<span class="hljs-variable">$this</span>-&gt;arr); <span class="hljs-comment">// 获取队尾元素</span><br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">clear</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">unset</span>(<span class="hljs-variable language_">$this</span>-&gt;arr); <span class="hljs-comment">// 清空队列</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;PHP-的生命周期是什么？&quot;&gt;&lt;a href=&quot;#PHP-的生命周期是什么？&quot; class=&quot;headerlink&quot; title=&quot;PHP 的生命周期是什么？&quot;&gt;&lt;/a&gt;PHP 的生命周期是什么？&lt;/h1&gt;&lt;p&gt;PHP 生命周期有5个阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;l</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="PHP" scheme="http://www.loquy.cn/tags/PHP/"/>
    
  </entry>
  
  <entry>
    <title>PHP 设计模式之单例模式（Singleton）</title>
    <link href="http://www.loquy.cn/posts/77dd5484.html"/>
    <id>http://www.loquy.cn/posts/77dd5484.html</id>
    <published>2020-06-22T08:08:19.000Z</published>
    <updated>2020-06-22T08:08:19.000Z</updated>
    
    <content type="html"><![CDATA[<p><strong>单例模式被公认为是 反面模式，为了获得更好的可测试性和可维护性，请使用『依赖注入模式』</strong></p><h3 id="1-8-1-目的"><a href="#1-8-1-目的" class="headerlink" title="1.8.1. 目的"></a>1.8.1. 目的</h3><p>在应用程序调用的时候，只能获得一个对象实例。</p><h3 id="1-8-2-例子"><a href="#1-8-2-例子" class="headerlink" title="1.8.2. 例子"></a>1.8.2. 例子</h3><p>数据库连接<br>日志 (多种不同用途的日志也可能会成为多例模式)<br>在应用中锁定文件 (系统中只存在一个 …)</p><h3 id="1-8-4-代码部分"><a href="#1-8-4-代码部分" class="headerlink" title="1.8.4. 代码部分"></a>1.8.4. 代码部分</h3><p>Singleton.php</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">DesignPatterns</span>\<span class="hljs-title class_">Creational</span>\<span class="hljs-title class_">Singleton</span>;<br><br><span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Singleton</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@var</span> Singleton</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-built_in">static</span> <span class="hljs-variable">$instance</span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 通过懒加载获得实例（在第一次使用的时候创建）</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getInstance</span>(<span class="hljs-params"></span>): <span class="hljs-title">Singleton</span></span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> === <span class="hljs-built_in">static</span>::<span class="hljs-variable">$instance</span>) &#123;<br>            <span class="hljs-built_in">static</span>::<span class="hljs-variable">$instance</span> = <span class="hljs-keyword">new</span> <span class="hljs-built_in">static</span>();<br>        &#125;<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-built_in">static</span>::<span class="hljs-variable">$instance</span>;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 不允许从外部调用以防止创建多个实例</span><br><span class="hljs-comment">    * 要使用单例，必须通过 Singleton::getInstance() 方法获取实例</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 防止实例被克隆（这会创建实例的副本）</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__clone</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * 防止反序列化（这将创建它的副本）</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__wakeup</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="1-8-5-测试"><a href="#1-8-5-测试" class="headerlink" title="1.8.5. 测试"></a>1.8.5. 测试</h3><p>Tests&#x2F;SingletonTest.php</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">DesignPatterns</span>\<span class="hljs-title class_">Creational</span>\<span class="hljs-title class_">Singleton</span>\<span class="hljs-title class_">Tests</span>;<br><br><span class="hljs-keyword">use</span> <span class="hljs-title">DesignPatterns</span>\<span class="hljs-title">Creational</span>\<span class="hljs-title">Singleton</span>\<span class="hljs-title">Singleton</span>;<br><span class="hljs-keyword">use</span> <span class="hljs-title">PHPUnit</span>\<span class="hljs-title">Framework</span>\<span class="hljs-title">TestCase</span>;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SingletonTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testUniqueness</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable">$firstCall</span> = <span class="hljs-title class_">Singleton</span>::<span class="hljs-title function_ invoke__">getInstance</span>();<br>        <span class="hljs-variable">$secondCall</span> = <span class="hljs-title class_">Singleton</span>::<span class="hljs-title function_ invoke__">getInstance</span>();<br><br>        <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">assertInstanceOf</span>(<span class="hljs-title class_">Singleton</span>::<span class="hljs-variable language_">class</span>, <span class="hljs-variable">$firstCall</span>);<br>        <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">assertSame</span>(<span class="hljs-variable">$firstCall</span>, <span class="hljs-variable">$secondCall</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure><p>————————————————<br>原文作者：PHP 技术论坛文档：《PHP 设计模式全集（2018）》<br>转自链接：<a href="https://learnku.com/docs/php-design-patterns/2018/Singleton/1494">https://learnku.com/docs/php-design-patterns/2018/Singleton/1494</a><br>版权声明：翻译文档著作权归译者和 LearnKu 社区所有</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;strong&gt;单例模式被公认为是 反面模式，为了获得更好的可测试性和可维护性，请使用『依赖注入模式』&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;1-8-1-目的&quot;&gt;&lt;a href=&quot;#1-8-1-目的&quot; class=&quot;headerlink&quot; title=&quot;1.8.1. 目</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="PHP" scheme="http://www.loquy.cn/tags/PHP/"/>
    
  </entry>
  
  <entry>
    <title>在 PHP 中使用 cURL</title>
    <link href="http://www.loquy.cn/posts/b4a5aa5.html"/>
    <id>http://www.loquy.cn/posts/b4a5aa5.html</id>
    <published>2020-06-10T09:15:08.000Z</published>
    <updated>2020-06-11T06:54:08.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="什么是cURL"><a href="#什么是cURL" class="headerlink" title="什么是cURL"></a>什么是cURL</h1><ul><li><p>先来看下维基百科的解释：</p><pre><code class="hljs">  cURL 是一个开源项目，主要的产品是 curl（命令行工具）和 libcurl（C语言的API库），两者功能均是：基于网络协议，对指定 URL 进行网络传输。  cURL 涉及是任何网络协议传输，不涉及对具体数据的具体处理。（如：html 的渲染等）</code></pre></li><li><p>简单讲就是我们不用浏览器，在curl命令行工具就可以访问任意网址</p></li><li><p>PHP中集成了cURL库，那么我们就可以在代码上使用它的功能</p></li></ul><h1 id="在PHP中使用cURL"><a href="#在PHP中使用cURL" class="headerlink" title="在PHP中使用cURL"></a>在PHP中使用cURL</h1><p>  使用 cURL 函数的基本思想是先使用 <strong>curl_init()</strong> 初始化 cURL 会话，接着可以通过 <strong>curl_setopt()</strong> 设置需要的全部选项，然后使用 <strong>curl_exec()</strong> 来执行会话，当执行完会话后使用 <strong>curl_close()</strong> 关闭会话</p><ul><li>其中最需要我们配置的是 curl_setopt() 这步,我们来看下这个函数的说明</li></ul>  <figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">/**</span><br><span class="hljs-comment">*  为 cURL 会话句柄设置选项。</span><br><span class="hljs-comment">*  <span class="hljs-doctag">@param</span> resource $ch 返回的 cURL 句柄</span><br><span class="hljs-comment">*  <span class="hljs-doctag">@param</span> int $option 需要设置的CURLOPT_XXX选项。</span><br><span class="hljs-comment">*  <span class="hljs-doctag">@param</span> mixed $value 将设置在option选项上的值，可以接收多种类型的参数。</span><br><span class="hljs-comment">*  <span class="hljs-doctag">@return</span> bool 成功时返回 TRUE， 或者在失败时返回 FALSE </span><br><span class="hljs-comment">*/</span><br><span class="hljs-title function_ invoke__">curl_setopt</span>( resource <span class="hljs-variable">$ch</span>, <span class="hljs-keyword">int</span> <span class="hljs-variable">$option</span>, <span class="hljs-keyword">mixed</span> <span class="hljs-variable">$value</span>) : <span class="hljs-keyword">bool</span><br><br><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * 为 cURL 传输会话批量设置选项</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> resource $ch 返回的 cURL 句柄</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> array $options 一个 array 用来确定将被设置的选项及其值。数组的键值必须是一个有效的curl_setopt()常量或者是它们对等的整数值。 </span><br><span class="hljs-comment"> */</span><br><span class="hljs-title function_ invoke__">curl_setopt_array</span>( resource <span class="hljs-variable">$ch</span>, <span class="hljs-keyword">array</span> <span class="hljs-variable">$options</span>) : <span class="hljs-keyword">bool</span><br></code></pre></td></tr></table></figure><ul><li><p><a href="https://www.php.net/curl_setopt">option参数选项和值具体看官方文档，用的时候在查询</a></p></li><li><p>我们看下官方文档中使用 cURL 发送 POST 和 GET 封装后的函数</p></li></ul>  <figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-comment">/** </span><br><span class="hljs-comment">* Send a POST requst using cURL                              </span><br><span class="hljs-comment">* <span class="hljs-doctag">@param</span> string $url to request </span><br><span class="hljs-comment">* <span class="hljs-doctag">@param</span> array $post values to send </span><br><span class="hljs-comment">* <span class="hljs-doctag">@param</span> array $options for cURL </span><br><span class="hljs-comment">* <span class="hljs-doctag">@return</span> string </span><br><span class="hljs-comment">*/</span> <br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curl_post</span>(<span class="hljs-params"><span class="hljs-variable">$url</span>, <span class="hljs-keyword">array</span> <span class="hljs-variable">$post</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>), <span class="hljs-keyword">array</span> <span class="hljs-variable">$options</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>)</span>) </span><br><span class="hljs-function"></span>&#123; <br>    <span class="hljs-variable">$defaults</span> = <span class="hljs-keyword">array</span>( <br>        CURLOPT_POST =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 发送 POST 请求</span><br>        CURLOPT_HEADER =&gt; <span class="hljs-number">0</span>, <span class="hljs-comment">// 启用时会将头文件的信息作为数据流输出，这边不启用。 </span><br>        CURLOPT_URL =&gt; <span class="hljs-variable">$url</span>, <span class="hljs-comment">// 需要获取的 URL 地址，也可以在curl_init() 初始化会话的时候</span><br>        CURLOPT_FRESH_CONNECT =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 强制获取一个新的连接，而不是缓存中的连接</span><br>        CURLOPT_RETURNTRANSFER =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 将curl_exec()获取的信息以字符串返回，而不是直接输出。</span><br>        CURLOPT_FORBID_REUSE =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 在完成交互以后强制明确的断开连接，不能在连接池中重用</span><br>        <span class="hljs-comment">// CURLOPT_TIMEOUT =&gt; 10, // 允许 cURL 函数执行的最长秒数，这边先不限制</span><br>        CURLOPT_POSTFIELDS =&gt; <span class="hljs-title function_ invoke__">http_build_query</span>(<span class="hljs-variable">$post</span>), <span class="hljs-comment">// 全部数据使用HTTP协议中的 &quot;POST&quot; 操作来发送，http_build_query返回一个 URL 编码后的字符串</span><br>        <span class="hljs-comment">// 以下两个设置是为了防止访问没有SSL证书的网站报错</span><br>        CURLOPT_SSL_VERIFYPEER =&gt; <span class="hljs-number">0</span>, <span class="hljs-comment">// 禁止 cURL 验证对等证书（peer&#x27;scertificate）。要验证的交换证书可以在 CURLOPT_CAINFO 选项中设置，或在 CURLOPT_CAPATH中设置证书目录。</span><br>        CURLOPT_SSL_VERIFYHOST =&gt; <span class="hljs-number">0</span> <span class="hljs-comment">// 设置为 1 是检查服务器SSL证书中是否存在一个公用名, 0 为不检查名称</span><br>    ); <br><br>    <span class="hljs-variable">$ch</span> = <span class="hljs-title function_ invoke__">curl_init</span>(); <br>    <span class="hljs-title function_ invoke__">curl_setopt_array</span>(<span class="hljs-variable">$ch</span>, (<span class="hljs-variable">$options</span> + <span class="hljs-variable">$defaults</span>));<br>    <span class="hljs-keyword">if</span>( ! <span class="hljs-variable">$result</span> = <span class="hljs-title function_ invoke__">curl_exec</span>(<span class="hljs-variable">$ch</span>)) <br>    &#123; <br>        <span class="hljs-title function_ invoke__">trigger_error</span>(<span class="hljs-title function_ invoke__">curl_error</span>(<span class="hljs-variable">$ch</span>)); <br>    &#125; <br>    <span class="hljs-title function_ invoke__">curl_close</span>(<span class="hljs-variable">$ch</span>); <br>    <span class="hljs-keyword">return</span> <span class="hljs-variable">$result</span>; <br>&#125; <br><br><span class="hljs-comment">/** </span><br><span class="hljs-comment">* Send a GET requst using cURL </span><br><span class="hljs-comment">* <span class="hljs-doctag">@param</span> string $url to request </span><br><span class="hljs-comment">* <span class="hljs-doctag">@param</span> array $get values to send </span><br><span class="hljs-comment">* <span class="hljs-doctag">@param</span> array $options for cURL </span><br><span class="hljs-comment">* <span class="hljs-doctag">@return</span> string </span><br><span class="hljs-comment">*/</span> <br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curl_get</span>(<span class="hljs-params"><span class="hljs-variable">$url</span>, <span class="hljs-keyword">array</span> <span class="hljs-variable">$get</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>), <span class="hljs-keyword">array</span> <span class="hljs-variable">$options</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>)</span>) </span><br><span class="hljs-function"></span>&#123;    <br>    <span class="hljs-variable">$defaults</span> = <span class="hljs-keyword">array</span>( <br>        CURLOPT_URL =&gt; <span class="hljs-variable">$url</span>. (<span class="hljs-title function_ invoke__">strpos</span>(<span class="hljs-variable">$url</span>, <span class="hljs-string">&#x27;?&#x27;</span>) === <span class="hljs-literal">FALSE</span> ? <span class="hljs-string">&#x27;?&#x27;</span> : <span class="hljs-string">&#x27;&#x27;</span>). <span class="hljs-title function_ invoke__">http_build_query</span>(<span class="hljs-variable">$get</span>), <span class="hljs-comment">// 需要获取的 URL 地址，也可以在curl_init() 初始化会话的时候。 </span><br>        CURLOPT_HEADER =&gt; <span class="hljs-number">0</span>, <span class="hljs-comment">// 启用时会将头文件的信息作为数据流输出。 </span><br>        CURLOPT_RETURNTRANSFER =&gt; <span class="hljs-literal">TRUE</span>, <br>        <span class="hljs-comment">// CURLOPT_TIMEOUT =&gt; 10,</span><br>        CURLOPT_SSL_VERIFYPEER =&gt; <span class="hljs-number">0</span>, <br>        CURLOPT_SSL_VERIFYHOST =&gt; <span class="hljs-number">0</span>            <br>    ); <br>    <br>    <span class="hljs-variable">$ch</span> = <span class="hljs-title function_ invoke__">curl_init</span>(); <br>    <span class="hljs-title function_ invoke__">curl_setopt_array</span>(<span class="hljs-variable">$ch</span>, (<span class="hljs-variable">$options</span> + <span class="hljs-variable">$defaults</span>)); <br>    <span class="hljs-keyword">if</span>( ! <span class="hljs-variable">$result</span> = <span class="hljs-title function_ invoke__">curl_exec</span>(<span class="hljs-variable">$ch</span>)) <br>    &#123; <br>        <span class="hljs-title function_ invoke__">trigger_error</span>(<span class="hljs-title function_ invoke__">curl_error</span>(<span class="hljs-variable">$ch</span>)); <br>    &#125; <br>    <span class="hljs-title function_ invoke__">curl_close</span>(<span class="hljs-variable">$ch</span>); <br>    <span class="hljs-keyword">return</span> <span class="hljs-variable">$result</span>; <br>&#125;<br></code></pre></td></tr></table></figure><h1 id="发送GET-POST请求到接口交互数据"><a href="#发送GET-POST请求到接口交互数据" class="headerlink" title="发送GET&#x2F;POST请求到接口交互数据"></a>发送GET&#x2F;POST请求到接口交互数据</h1><ul><li><p>首先我们得有个运行PHP的环境，我这边使用 PHPStudy</p></li><li><p>其次在站点域名那里配置我们测试的 demo 的域名</p></li></ul><p><img src="https://www.loquy.cn/images/1591845702.jpg" alt="phpStudy"></p><ul><li><p>以下为测试 demo</p><p>新建两个 php 文件：一个是提供数据的接口，创建一个数组然后转成 json 格式输出到浏览器；另个是使用 curl 获取数据的接口，使用上面封装好的 curl_get 和 curl_post 函数获取数据。</p></li></ul><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 提供数据的类，</span><br><span class="hljs-comment"> */</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Data</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">creatData</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable">$data</span> = [<span class="hljs-string">&#x27;car&#x27;</span>=&gt;<span class="hljs-string">&#x27;Benz&#x27;</span>,<span class="hljs-string">&#x27;book&#x27;</span>=&gt;<span class="hljs-string">&#x27;Little Prince&#x27;</span>,<span class="hljs-string">&#x27;house&#x27;</span>=&gt;<span class="hljs-string">&#x27;The Ocean Villas&#x27;</span>];<br>        <span class="hljs-keyword">echo</span> <span class="hljs-title function_ invoke__">json_encode</span>(<span class="hljs-variable">$data</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-variable">$data</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Data</span>;<br><span class="hljs-variable">$data</span>-&gt;<span class="hljs-title function_ invoke__">creatData</span>();<br></code></pre></td></tr></table></figure><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><code class="hljs php"><span class="hljs-meta">&lt;?php</span><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">* 获取数据的类</span><br><span class="hljs-comment">*/</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GetData</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-variable">$url</span> = <span class="hljs-string">&#x27;http://127.0.0.1:1000/data.php&#x27;</span>;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test_curl_get</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable">$result</span> = <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">curl_get</span>(<span class="hljs-variable">$this</span>-&gt;url);<br>        <span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-title function_ invoke__">json_decode</span>(<span class="hljs-variable">$result</span>,<span class="hljs-literal">true</span>));<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test_curl_post</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable">$result</span> = <span class="hljs-variable language_">$this</span>-&gt;<span class="hljs-title function_ invoke__">curl_post</span>(<span class="hljs-variable">$this</span>-&gt;url);<br>        <span class="hljs-title function_ invoke__">var_dump</span>(<span class="hljs-title function_ invoke__">json_decode</span>(<span class="hljs-variable">$result</span>,<span class="hljs-literal">true</span>));<br>    &#125;<br>    <br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * Send a POST requst using cURL</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> string $url to request</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> array $post values to send</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> array $options for cURL</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> string</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curl_post</span>(<span class="hljs-params"><span class="hljs-variable">$url</span>, <span class="hljs-keyword">array</span> <span class="hljs-variable">$post</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>), <span class="hljs-keyword">array</span> <span class="hljs-variable">$options</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>)</span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable">$defaults</span> = <span class="hljs-keyword">array</span>(<br>            CURLOPT_POST =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 发送 POST 请求</span><br>            CURLOPT_HEADER =&gt; <span class="hljs-number">0</span>, <span class="hljs-comment">// 启用时会将头文件的信息作为数据流输出，这边不启用。</span><br>            CURLOPT_URL =&gt; <span class="hljs-variable">$url</span>, <span class="hljs-comment">// 需要获取的 URL 地址，也可以在curl_init() 初始化会话的时候</span><br>            CURLOPT_FRESH_CONNECT =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 强制获取一个新的连接，而不是缓存中的连接</span><br>            CURLOPT_RETURNTRANSFER =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 将curl_exec()获取的信息以字符串返回，而不是直接输出。</span><br>            CURLOPT_FORBID_REUSE =&gt; <span class="hljs-number">1</span>, <span class="hljs-comment">// 在完成交互以后强制明确的断开连接，不能在连接池中重用</span><br>            <span class="hljs-comment">// CURLOPT_TIMEOUT =&gt; 10, // 允许 cURL 函数执行的最长秒数，这边先不限制</span><br>            CURLOPT_POSTFIELDS =&gt; <span class="hljs-title function_ invoke__">http_build_query</span>(<span class="hljs-variable">$post</span>), <span class="hljs-comment">// 全部数据使用HTTP协议中的 &quot;POST&quot; 操作来发送，http_build_query返回一个 URL 编码后的字符串</span><br>            <span class="hljs-comment">// 以下两个设置是为了防止访问没有SSL证书的网站报错</span><br>            CURLOPT_SSL_VERIFYPEER =&gt; <span class="hljs-number">0</span>, <span class="hljs-comment">// 禁止 cURL 验证对等证书（peer&#x27;scertificate）。要验证的交换证书可以在 CURLOPT_CAINFO 选项中设置，或在 CURLOPT_CAPATH中设置证书目录。</span><br>            CURLOPT_SSL_VERIFYHOST =&gt; <span class="hljs-number">0</span> <span class="hljs-comment">// 设置为 1 是检查服务器SSL证书中是否存在一个公用名, 0 为不检查名称</span><br>        );<br><br>        <span class="hljs-variable">$ch</span> = <span class="hljs-title function_ invoke__">curl_init</span>();<br>        <span class="hljs-title function_ invoke__">curl_setopt_array</span>(<span class="hljs-variable">$ch</span>, (<span class="hljs-variable">$options</span> + <span class="hljs-variable">$defaults</span>));<br>        <span class="hljs-keyword">if</span> (! <span class="hljs-variable">$result</span> = <span class="hljs-title function_ invoke__">curl_exec</span>(<span class="hljs-variable">$ch</span>)) &#123;<br>            <span class="hljs-title function_ invoke__">trigger_error</span>(<span class="hljs-title function_ invoke__">curl_error</span>(<span class="hljs-variable">$ch</span>));<br>        &#125;<br>        <span class="hljs-title function_ invoke__">curl_close</span>(<span class="hljs-variable">$ch</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable">$result</span>;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">    * Send a GET requst using cURL</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> string $url to request</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> array $get values to send</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@param</span> array $options for cURL</span><br><span class="hljs-comment">    * <span class="hljs-doctag">@return</span> string</span><br><span class="hljs-comment">    */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curl_get</span>(<span class="hljs-params"><span class="hljs-variable">$url</span>, <span class="hljs-keyword">array</span> <span class="hljs-variable">$get</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>), <span class="hljs-keyword">array</span> <span class="hljs-variable">$options</span> = <span class="hljs-keyword">array</span>(<span class="hljs-params"></span>)</span>)</span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-variable">$defaults</span> = <span class="hljs-keyword">array</span>(<br>            CURLOPT_URL =&gt; <span class="hljs-variable">$url</span>. (<span class="hljs-title function_ invoke__">strpos</span>(<span class="hljs-variable">$url</span>, <span class="hljs-string">&#x27;?&#x27;</span>) === <span class="hljs-literal">false</span> ? <span class="hljs-string">&#x27;?&#x27;</span> : <span class="hljs-string">&#x27;&#x27;</span>). <span class="hljs-title function_ invoke__">http_build_query</span>(<span class="hljs-variable">$get</span>), <span class="hljs-comment">// 需要获取的 URL 地址，也可以在curl_init() 初始化会话的时候。</span><br>            CURLOPT_HEADER =&gt; <span class="hljs-number">0</span>, <span class="hljs-comment">// 启用时会将头文件的信息作为数据流输出。</span><br>            CURLOPT_RETURNTRANSFER =&gt; <span class="hljs-literal">true</span>,<br>            <span class="hljs-comment">// CURLOPT_TIMEOUT =&gt; 10,</span><br>            CURLOPT_SSL_VERIFYPEER =&gt; <span class="hljs-number">0</span>,<br>            CURLOPT_SSL_VERIFYHOST =&gt; <span class="hljs-number">0</span><br>        );<br>        <br>        <span class="hljs-variable">$ch</span> = <span class="hljs-title function_ invoke__">curl_init</span>();<br>        <span class="hljs-title function_ invoke__">curl_setopt_array</span>(<span class="hljs-variable">$ch</span>, (<span class="hljs-variable">$options</span> + <span class="hljs-variable">$defaults</span>));<br>        <span class="hljs-keyword">if</span> (! <span class="hljs-variable">$result</span> = <span class="hljs-title function_ invoke__">curl_exec</span>(<span class="hljs-variable">$ch</span>)) &#123;<br>            <span class="hljs-title function_ invoke__">trigger_error</span>(<span class="hljs-title function_ invoke__">curl_error</span>(<span class="hljs-variable">$ch</span>));<br>        &#125;<br>        <span class="hljs-title function_ invoke__">curl_close</span>(<span class="hljs-variable">$ch</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-variable">$result</span>;<br>    &#125;<br>&#125;<br><br><span class="hljs-variable">$GetData</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">GetData</span>;<br><span class="hljs-variable">$GetData</span>-&gt;<span class="hljs-title function_ invoke__">test_curl_get</span>();<br><span class="hljs-variable">$GetData</span>-&gt;<span class="hljs-title function_ invoke__">test_curl_post</span>();<br><br></code></pre></td></tr></table></figure><ul><li>在浏览器访问写好的 demo</li></ul><p><img src="https://www.loquy.cn/images/1591846206.jpg" alt="phpStudy"></p><p><img src="https://www.loquy.cn/images/1591846227.jpg" alt="phpStudy"></p><p><strong>到此便使用curl成功获取到数据</strong></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;什么是cURL&quot;&gt;&lt;a href=&quot;#什么是cURL&quot; class=&quot;headerlink&quot; title=&quot;什么是cURL&quot;&gt;&lt;/a&gt;什么是cURL&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;先来看下维基百科的解释：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="PHP" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/PHP/"/>
    
    
    <category term="PHP" scheme="http://www.loquy.cn/tags/PHP/"/>
    
    <category term="cURL" scheme="http://www.loquy.cn/tags/cURL/"/>
    
  </entry>
  
  <entry>
    <title>使用 Github Pages 和 Hexo 搭建博客</title>
    <link href="http://www.loquy.cn/posts/3b0a6c12.html"/>
    <id>http://www.loquy.cn/posts/3b0a6c12.html</id>
    <published>2020-05-26T07:59:13.000Z</published>
    <updated>2020-10-13T03:40:12.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="项目简介"><a href="#项目简介" class="headerlink" title="项目简介"></a>项目简介</h1><p>当前项目是使用 <a href="https://pages.github.com/">Github Pages</a> 和 <a href="https://hexo.io/zh-cn/docs/">Hexo</a> 搭建的静态博客</p><pre><code class="hljs">Github Pages 是 GitHub 提供的一个网页寄存服务，于 2008 年推出。可以用于存放静态网页，包括博客、项目文档甚至整本书。Jekyll 软件可以用于将文档转换成静态网页，该软件提供了将网页上传到 Github Pages 的功能。一般 Github Pages 的网站使用 github.io 的子域名，但是用户也可以使用第三方域名。Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown（或其他渲染引擎）解析文章，在几秒内，即可利用靓丽的主题生成静态网页。</code></pre><ul><li>首先搭建 Github Pages</li><li>然后使用 Hexo 部署到 Github 远程仓库</li></ul><h2 id="Github-Pages-的搭建方式"><a href="#Github-Pages-的搭建方式" class="headerlink" title="Github Pages 的搭建方式"></a>Github Pages 的搭建方式</h2><p>如果之前未使用过 Git，可以学习，<a href="http://rogerdudler.github.io/git-guide/index.zh.html">Git 小白教程</a></p><ul><li>创建名为 username.github.io 的仓库，username 是你的 github 的用户名，不是昵称</li><li>克隆到本地<br>  git clone <a href="https://github.com/username/username.github.io">https://github.com/username/username.github.io</a></li><li>进入文件夹创建 index.html 文件</li><li>推送到 github 远程仓库<br>  git add –all<br>  git commit -m “Initial commit”<br>  git push -u origin master</li><li>搭建完成，在浏览器打开 <a href="https://username.github.io/">https://username.github.io</a> 即可访问</li></ul><h2 id="Hexo-安装"><a href="#Hexo-安装" class="headerlink" title="Hexo 安装"></a>Hexo 安装</h2><h3 id="安装前提"><a href="#安装前提" class="headerlink" title="安装前提"></a>安装前提</h3><p>安装 hexo 相当简单，只需要先安装下列应用程序即可：</p><ul><li><a href="https://nodejs.org/en/">Node.js</a></li><li><a href="https://git-scm.com/">Git</a></li></ul><h3 id="安装-Hexo"><a href="#安装-Hexo" class="headerlink" title="安装 Hexo"></a>安装 Hexo</h3><p>所有必备的应用程序安装完成后，即可使用 npm 安装 hexo。</p><pre><code class="hljs">$ npm install -g hexo-cli</code></pre><p>对于熟悉 npm 的进阶用户，可以仅局部安装 Hexo 包。</p><pre><code class="hljs">$ npm install hexo</code></pre><h3 id="新建一个网站和启动服务器运行"><a href="#新建一个网站和启动服务器运行" class="headerlink" title="新建一个网站和启动服务器运行"></a>新建一个网站和启动服务器运行</h3><pre><code class="hljs">$ hexo init &lt;folder&gt; 如果没有设置 folder hexo 默认在目前的文件夹建立网站$ hexo server 简写 $ hexo s 默认情况下，访问网址为： http://localhost:4000/</code></pre><h3 id="部署到-Github-Pages"><a href="#部署到-Github-Pages" class="headerlink" title="部署到 Github Pages"></a>部署到 Github Pages</h3><ul><li><p>编辑 <strong>_config.yml</strong> 配置文件</p><pre><code class="hljs">  deploy:      type: git      repo: https://github.com/username/username.github.io.git      branch: master  </code></pre></li><li><p><strong>hexo generate</strong> 生成静态文件。</p></li><li><p><strong>hexo deploy</strong></p></li><li><p>以上两步可以简写为 <strong>hexo g -d</strong> 或 <strong>hexo d -g</strong></p></li></ul><h2 id="Hexo-目录结构"><a href="#Hexo-目录结构" class="headerlink" title="Hexo 目录结构"></a>Hexo 目录结构</h2><pre><code class="hljs">.├── _config.yml ├── package.json├── scaffolds├── source|   ├── _drafts|   └── _posts└── themes└── node_modules└── public└── .deploy_git</code></pre><h3 id="config-yml"><a href="#config-yml" class="headerlink" title="_config.yml"></a>_config.yml</h3><p><a href="https://hexo.io/zh-cn/docs/configuration">Hexo配置文件</a></p><h3 id="package-json"><a href="#package-json" class="headerlink" title="package.json"></a>package.json</h3><p>应用程序的信息</p><h3 id="scaffolds"><a href="#scaffolds" class="headerlink" title="scaffolds"></a>scaffolds</h3><p>模版件夹。当您新建文章时，Hexo 会根据 scaffold 来建立文件。Hexo 的模板是指在新建的文章文件中默认填充的内容。</p><h3 id="source"><a href="#source" class="headerlink" title="source"></a>source</h3><p>资源文件夹是存放用户资源的地方。除 _posts 文件夹之外，开头命名为 _ (下划线)的文件 &#x2F; 文件夹和隐藏的文件将会被忽略。Markdown 和 HTML 文件会被解析并放到 public 文件夹，而其他文件会被拷贝过去。</p><h3 id="themes"><a href="#themes" class="headerlink" title="themes"></a>themes</h3><p>主题文件夹。Hexo 会根据主题来生成静态页面。</p><h3 id="特殊目录"><a href="#特殊目录" class="headerlink" title="特殊目录"></a>特殊目录</h3><ul><li>node_modules， <strong>npm install hexo</strong> 生成的包和依赖</li><li>public ，<strong>hexo g</strong> 部署之前预先生成的静态文件</li><li>.deploy_git， <strong>hexo d</strong> 部署提交到 git 主干的目录</li></ul><h2 id="Hexo-发布文章"><a href="#Hexo-发布文章" class="headerlink" title="Hexo 发布文章"></a>Hexo 发布文章</h2><ul><li>创建文章 <strong>hexo new “article title”</strong></li><li>本地预览 <strong>hexo server</strong></li><li>部署网站 <strong>hexo g -d</strong> 或 <strong>hexo d -g</strong></li></ul><h2 id="多台电脑同步-Hexo-版本"><a href="#多台电脑同步-Hexo-版本" class="headerlink" title="多台电脑同步 Hexo 版本"></a>多台电脑同步 Hexo 版本</h2><p><strong>问题：远程仓库存的是静态文件，换电脑就无法使用 hexo</strong><br><strong>解决思路：创建分支管理 hexo 源代码</strong></p><ul><li><p>克隆 username.github.io 仓库到本地</p><pre><code class="hljs">  git clone https://github.com/username/username.github.io.git</code></pre></li><li><p>除 git 外的文件都删掉</p></li><li><p>整个 hexo 文件复制过来</p></li><li><p>切换并创建一个叫 hexo 的分支</p><pre><code class="hljs">  git checkout -b Hexo</code></pre></li><li><p>提交到 hexo 分支</p><pre><code class="hljs">  git add .  git commit -m &quot;新建分支&quot;  git remote add origin https://github.com/username/username.github.io.git  git push -u origin hexo</code></pre></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;项目简介&quot;&gt;&lt;a href=&quot;#项目简介&quot; class=&quot;headerlink&quot; title=&quot;项目简介&quot;&gt;&lt;/a&gt;项目简介&lt;/h1&gt;&lt;p&gt;当前项目是使用 &lt;a href=&quot;https://pages.github.com/&quot;&gt;Github Pages&lt;/a&gt; 和</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Git" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Git/"/>
    
    <category term="Hexo" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Hexo/"/>
    
    
    <category term="Hexo" scheme="http://www.loquy.cn/tags/Hexo/"/>
    
    <category term="Github Pages" scheme="http://www.loquy.cn/tags/Github-Pages/"/>
    
  </entry>
  
  <entry>
    <title>Vue 基础知识总结</title>
    <link href="http://www.loquy.cn/posts/1cd82901.html"/>
    <id>http://www.loquy.cn/posts/1cd82901.html</id>
    <published>2020-05-23T02:33:22.000Z</published>
    <updated>2020-05-23T02:33:22.000Z</updated>
    
    <content type="html"><![CDATA[<h6 id="一、常用指令"><a href="#一、常用指令" class="headerlink" title="一、常用指令"></a>一、常用指令</h6><ul><li>v-on 绑定一个事件 缩写 @ 在 methods 类方法里面操作绑定的方法</li><li>v-bind 绑定一个属性 缩写 : 在 data 数据对象里面操作绑定的数据</li><li>v-model 双向绑定通常用于获取 input 框输入的内容，无论那边更改都会同步值</li><li>v-for 基于数组或对象来循环渲染一个列表，语法：<br> 1.循环数组，index 是数组的索引 <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">v-<span class="hljs-keyword">for</span>=<span class="hljs-string">&quot;(item,index) in items&quot;</span> :key=<span class="hljs-string">&quot;index&quot;</span><br></code></pre></td></tr></table></figure> 2.循环对象，name 是对象的键值  <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">v-<span class="hljs-keyword">for</span>=<span class="hljs-string">&quot;(value, name, index) in object&quot;</span> :key=<span class="hljs-string">&quot;index&quot;</span><br></code></pre></td></tr></table></figure> 3.为什么使用 v-for 时必须添加唯一的 key?<br>使用 v-for 更新已渲染的元素列表时，默认用就地复用策略;<br>列表数据修改的时候，他会根据 key 值去判断某个值是否修改，如果修改，则重新渲染这一项，否则复用之前的元素</li><li>v-if v-else v-else-if 动态添加或删除元素</li><li>v-show 添加元素的 display 样式控制显示或隐藏</li><li>v-html 输出 html 代码</li></ul><h6 id="二、常用属性"><a href="#二、常用属性" class="headerlink" title="二、常用属性"></a>二、常用属性</h6><table><thead><tr><th align="left">属性写法</th><th align="left">名称</th><th align="left">作用</th></tr></thead><tbody><tr><td align="left">data: {}</td><td align="left">数据属性</td><td align="left">用来存放需要绑定的数据</td></tr><tr><td align="left">methods: {}</td><td align="left">事件操作属性</td><td align="left">用来放定义的事件方法</td></tr><tr><td align="left">components: {}</td><td align="left">组件属性</td><td align="left">自定义组件声明</td></tr><tr><td align="left">props: {}</td><td align="left">获取父组件数据</td><td align="left">单向绑定</td></tr><tr><td align="left">computed: {}</td><td align="left">计算属性</td><td align="left">提供相对简单的数据计算</td></tr><tr><td align="left">watch: {}</td><td align="left">侦听器</td><td align="left">观察某一特定question的值</td></tr><tr><td align="left">directives: {}</td><td align="left">自定义指令属性</td><td align="left">注册内部自定义指令</td></tr><tr><td align="left">filters: {}</td><td align="left">过滤器</td><td align="left">自定义过滤器</td></tr><tr><td align="left">…</td><td align="left"></td><td align="left"></td></tr></tbody></table><h6 id="三、文件结构"><a href="#三、文件结构" class="headerlink" title="三、文件结构"></a>三、文件结构</h6> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;template&gt;<br>  <span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example&quot;</span>&gt;</span>&#123;&#123; msg &#125;&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span><br>&lt;/template&gt;<br><br><span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="language-javascript"><span class="language-xml"><span class="hljs-keyword">import</span> otherComponent <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;./OtherComponent.vue&#x27;</span></span></span><br><span class="language-javascript"><span class="language-xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;</span></span><br><span class="language-javascript"><span class="language-xml">    <span class="hljs-comment">// 常用属性</span></span></span><br><span class="language-javascript"><span class="language-xml">    <span class="hljs-attr">components</span>: &#123;</span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-comment">// 组件注册</span></span></span><br><span class="language-javascript"><span class="language-xml">      otherComponent</span></span><br><span class="language-javascript"><span class="language-xml">    &#125;,</span></span><br><span class="language-javascript"><span class="language-xml">    data () &#123; </span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-keyword">return</span> &#123;</span></span><br><span class="language-javascript"><span class="language-xml">        <span class="hljs-comment">// 自定义数据</span></span></span><br><span class="language-javascript"><span class="language-xml">        <span class="hljs-attr">msg</span>: <span class="hljs-string">&#x27;Hello world!&#x27;</span></span></span><br><span class="language-javascript"><span class="language-xml">      &#125;</span></span><br><span class="language-javascript"><span class="language-xml">    &#125;,    </span></span><br><span class="language-javascript"><span class="language-xml">    create () &#123;</span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-comment">// 初始化</span></span></span><br><span class="language-javascript"><span class="language-xml">    &#125;,</span></span><br><span class="language-javascript"><span class="language-xml">    mounted () &#123;</span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-comment">// 挂载</span></span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">getData</span>()</span></span><br><span class="language-javascript"><span class="language-xml">    &#125;,</span></span><br><span class="language-javascript"><span class="language-xml">    <span class="hljs-attr">methods</span>: &#123;</span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-comment">// 自定义方法</span></span></span><br><span class="language-javascript"><span class="language-xml">      <span class="hljs-title function_">getData</span>(<span class="hljs-params"></span>)&#123;</span></span><br><span class="language-javascript"><span class="language-xml">          <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;success&#x27;</span>)</span></span><br><span class="language-javascript"><span class="language-xml">      &#125;</span></span><br><span class="language-javascript"><span class="language-xml">    &#125;</span></span><br><span class="language-javascript"><span class="language-xml">&#125;</span></span><br><span class="language-javascript"><span class="language-xml"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span><br><br><span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="language-css"><span class="language-xml">  <span class="hljs-selector-class">.example</span> &#123;</span></span><br><span class="language-css"><span class="language-xml">    <span class="hljs-attribute">color</span>: red;</span></span><br><span class="language-css"><span class="language-xml">  &#125;</span></span><br><span class="language-css"><span class="language-xml"></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span><br><br></code></pre></td></tr></table></figure><h6 id="四、生命周期"><a href="#四、生命周期" class="headerlink" title="四、生命周期"></a>四、生命周期</h6><p><img src="https://cn.vuejs.org/images/lifecycle.png" alt="avatar"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h6 id=&quot;一、常用指令&quot;&gt;&lt;a href=&quot;#一、常用指令&quot; class=&quot;headerlink&quot; title=&quot;一、常用指令&quot;&gt;&lt;/a&gt;一、常用指令&lt;/h6&gt;&lt;ul&gt;
&lt;li&gt;v-on 绑定一个事件 缩写 @ 在 methods 类方法里面操作绑定的方法&lt;/li&gt;
&lt;li</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="JavaScript" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/JavaScript/"/>
    
    <category term="Vue" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/JavaScript/Vue/"/>
    
    
    <category term="Vue" scheme="http://www.loquy.cn/tags/Vue/"/>
    
  </entry>
  
  <entry>
    <title>Hello Hexo</title>
    <link href="http://www.loquy.cn/posts/a1751c09.html"/>
    <id>http://www.loquy.cn/posts/a1751c09.html</id>
    <published>2020-05-23T02:33:21.000Z</published>
    <updated>2020-05-26T15:11:21.000Z</updated>
    
    <content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo new <span class="hljs-string">&quot;My New Post&quot;</span><br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo server<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo generate<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo deploy<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.io/docs/&quot;&gt;documentation&lt;/a&gt; for</summary>
      
    
    
    
    <category term="编程" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/"/>
    
    <category term="Hexo" scheme="http://www.loquy.cn/categories/%E7%BC%96%E7%A8%8B/Hexo/"/>
    
    
    <category term="Hexo" scheme="http://www.loquy.cn/tags/Hexo/"/>
    
  </entry>
  
</feed>
