<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>后台框架 &#8211; 个人随笔</title>
	<atom:link href="/classify/%E5%90%8E%E5%8F%B0%E6%A1%86%E6%9E%B6/feed" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description></description>
	<lastBuildDate>Mon, 11 Jul 2022 08:06:24 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.1</generator>

<image>
	<url>/wp-content/uploads/2022/01/cropped-截屏2022-01-01-18.57.09-32x32.png</url>
	<title>后台框架 &#8211; 个人随笔</title>
	<link>/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>[避坑指南] Laravel知多少(&#x1f464;个人总结)</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/laravel/8954.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/laravel/8954.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 19 Mar 2022 03:54:50 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[资料]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[laravel知多少]]></category>
		<category><![CDATA[个人总结]]></category>
		<category><![CDATA[避坑指南]]></category>
		<guid isPermaLink="false">/?p=8954</guid>

					<description><![CDATA[面试php的时候总是会被问到，你对你现在用的框架了解多少？有哪些优缺点？如果你用过多个框架的话，还会被用来框架 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>面试php的时候总是会被问到，你对你现在用的框架了解多少？有哪些优缺点？如果你用过多个框架的话，还会被用来框架与框架做对比。</p>



<p>没办法，<strong>面试造航母，上班拧螺丝</strong>。以是程序员的常态。只能好好对待。</p>



<p>目前所在项目用的是Laravel框架，下面是自己个人对这个框架的总结吧，应该还有很多漏掉的，你也可以在留言处做补充。关键还是 要如何去回答 面试官 。希望能对你面试 用Laravel 有些许帮助吧！</p>



<p><strong>laravel框架最大的特点和优秀之处就是集合了php比较新的特点,以及各种各样的设计模式,Ioc模式,依赖注入等</strong></p>



<h2 class="wp-block-heading"><strong>一、Laravel有哪些特点</strong></h2>



<p>1 强大的rest router:用简单的回调函数就可以调用,快速绑定controller和router</p>



<p>2 artisan:命令行工具,很多手动的工作都自动化</p>



<p>3 可继承的模板,简化view的开发和管理</p>



<p>4 blade模板:渲染速度更快</p>



<p>5 ORM操作数据库</p>



<p>6 migration:管理数据库和版本控制</p>



<p>7 测试功能也很强大</p>



<p>8 composer也是亮点</p>



<p>9 队列</p>



<p>10 定时任务等</p>



<h2 class="wp-block-heading"><strong>二、架构模式</strong></h2>



<p>laravel框架是使用了服务组件化的开发模式，由多个服务提供者构成了组件，再由多个组件提供不同的服务，然后是多个服务构成了项目。</p>



<p>服务提供者是应用配置的核心，是通过 register方法中绑定服务到服务容器的。</p>



<h2 class="wp-block-heading"><strong>三、涉及到的设计模式</strong></h2>



<p>laravel框架使用了大量设计模式，使模块之间耦合度很低，服务容器可以方便的扩展框架功能以及编写测试。</p>



<p>1.ORM &#8211; 对象关系映射模式</p>



<p>2 依赖注入与IOC容器 &#8211; 策略模式</p>



<p>3 监听与触发&nbsp; &#8211;&nbsp; 观察者模式</p>



<p>4 门面模式 &#8211; 静态代理</p>



<p>5 注册树模式&nbsp; &#8211;&nbsp; 比如app.php里用到的数组存储</p>



<p>还有其他的，比如注册门面的时候用到单例模式app()-&gt;singleton等。</p>



<h2 class="wp-block-heading"><strong>四、服务方面</strong></h2>



<p>能快速开发出功能，自带各种方便的服务，比如数据验证、队列、缓存、数据迁移、测试、artisan 命令行等等，还有强大的 ORM，artisan强大的命令行工具，实现自动化。</p>



<p>Laravel安全功能有效地利用了盐散列和加密码机制，Bcrypt哈希算法”来创建加密密码。</p>



<h2 class="wp-block-heading"><strong>五、框架的其他知识点</strong></h2>



<p><strong>服务容器：</strong>是一个用于管理类依赖和执行依赖注入的强大工具。其实质是通过构造函数或者某些情况下通过「setter」方法将类依赖注入到类中。&nbsp;</p>



<p><strong>门面：</strong>为应用服务容器中的绑定类提供了一个「静态」接口 ，优点：在维护时能够提供更加易于测试、更加灵活、简明优雅的语法。</p>



<p><strong>契约：</strong>用来规划服务提供者的格式、方法、参数等，给服务提供者规范了一定约束。</p>



<p><strong>反射：</strong>主要用来动态地获取系统中类、实例对象、方法等语言构件的信息，通过发射API函数可以实现对这些语言构件信息的动态获取和动态操作等。主要用在ORM</p>



<p><strong>后期静态绑定：</strong>用于在继承范围内引用静态调用的类，即在类的继承过程中，使用的类不再是当前类，而是调用的类。</p>



<h2 class="wp-block-heading"><strong>六、生命周期</strong></h2>



<p>生命周期我是这样总结的：</p>



<p>入口文件 -&gt; 请求web服务器导入这个文件&nbsp; -&gt; 载入 Composer 生成的自动加载启动核心文件 -&gt; 内核启动(服务提供者启动框架的各种组件) -&gt; 交给路由分发到到（控制器，中间件等）-&gt; 逻辑处理&nbsp; &nbsp;-&gt; 返回结果</p>



<h2 class="wp-block-heading"><strong>七、laravel框架运用到的repository模式的主要思想</strong></h2>



<p>建立一个数据操作代理层，把controller里的数据操作剥离出来，这样做有几个好处：</p>



<p>1 把数据处理逻辑分离使得代码更容易维护</p>



<p>2 数据处理逻辑和业务逻辑分离，可以对这两个代码分别进行测试</p>



<p>3 减少代码重复</p>



<p>4 降低代码出错的几率</p>



<p>5 让controller代码的可读性大大提高&nbsp;</p>



<pre class="wp-block-preformatted">还有其他的，大家可以留言做总结哈！<br><br></pre>



<p><strong>以上是本文的全部内容，希望对大家的学习有帮助，觉得有用，有需要就支持一下吧</strong></p>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/laravel/8954.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>LaravelV8.6.10</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/laravel/8773.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/laravel/8773.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 25 Dec 2021 12:43:38 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Laravel8]]></category>
		<category><![CDATA[MAC]]></category>
		<category><![CDATA[MAMP PRO]]></category>
		<category><![CDATA[NUXT]]></category>
		<category><![CDATA[PhpStorm]]></category>
		<guid isPermaLink="false">/?p=8773</guid>

					<description><![CDATA[LaravelV8.6.10]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Mac下搭建Laravel环境（V8.6.10）</h2>



<p><a rel="noreferrer noopener" href="/goto/cdc2" rel="nofollow" data-type="URL" data-id="https://github.com/LeeYouRan/Server-Laravel" target="_blank">Dem</a><a href="/goto/cdc2" data-type="URL" data-id="https://github.com/LeeYouRan/Server-Laravel" target="_blank" rel="nofollow noreferrer noopener">o</a></p>



<p>1.需要<strong>的安装文件 Mamp Pro &amp; Phpstrom</strong></p>



<p><a rel="noreferrer noopener" href="/goto/sz79" rel="nofollow" data-type="URL" data-id="https://www.digit77.com/macapps/mamp-pro/" target="_blank">MAMP Pro 6.6 fix – 快速安装PHP/MySQL开发环境</a></p>



<p><a rel="noreferrer noopener" href="/goto/h92h" rel="nofollow" data-type="URL" data-id="https://www.jetbrains.com/phpstorm/download/download-thanks.html?platform=mac" target="_blank">PhpStorm 2021.3</a></p>



<p><a href="/goto/1ib6" data-type="URL" data-id="https://product-downloads.atlassian.com/software/sourcetree/ga/Sourcetree_4.1.5_241.zip" target="_blank" rel="nofollow noreferrer noopener">SourceTree 4.1.5</a></p>



<p><a rel="noreferrer noopener" href="/goto/hzn6" rel="nofollow" data-type="URL" data-id="https://www.digit77.com/macapps/navicat-premium/#download-explan" target="_blank">Navicat Premium 15.0.30</a></p>



<p><a href="/goto/0bi5" data-type="URL" data-id="https://www.digit77.com/macapps/another-redis-desktop-manager/#download-explan" target="_blank" rel="nofollow noreferrer noopener">Another Redis Desktop Manager 1.5.0</a>&nbsp;</p>



<p><strong>2.安装Laravel</strong></p>



<p><a rel="noreferrer noopener" href="/goto/b2ff" rel="nofollow" data-type="URL" data-id="https://www.jianshu.com/p/5b0718f1fe93" target="_blank">Mac下安装Laravel</a> </p>



<p><strong>3.配置开发环境</strong></p>



<p><a rel="noreferrer noopener" href="/goto/atqc" rel="nofollow" data-type="URL" data-id="https://blog.csdn.net/weixin_44103733/article/details/113749546" target="_blank">MAMP搭建Laravel虚拟机环境</a></p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-20.28.56.png"><img fetchpriority="high" decoding="async" width="2880" height="1800" src="/wp-content/uploads/2021/12/截屏2021-12-25-20.28.56.png" alt="" class="wp-image-8800" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-20.28.56.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-25-20.28.56-300x188.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-20.28.56-1024x640.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-25-20.28.56-768x480.png 768w, /wp-content/uploads/2021/12/截屏2021-12-25-20.28.56-1536x960.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-25-20.28.56-2048x1280.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /></a></figure>



<p><strong>4.伪静态</strong></p>



<p><a rel="noreferrer noopener" href="/goto/4qjo" rel="nofollow" data-type="URL" data-id="https://blog.csdn.net/qq_41150667/article/details/79156465" target="_blank">laravel+Apache 解决路由404问题</a></p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-20.34.25.png"><img decoding="async" width="2880" height="1800" src="/wp-content/uploads/2021/12/截屏2021-12-25-20.34.25.png" alt="" class="wp-image-8804" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-20.34.25.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-25-20.34.25-300x188.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-20.34.25-1024x640.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-25-20.34.25-768x480.png 768w, /wp-content/uploads/2021/12/截屏2021-12-25-20.34.25-1536x960.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-25-20.34.25-2048x1280.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /></a></figure>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-20.33.43.png"><img decoding="async" width="2880" height="1800" src="/wp-content/uploads/2021/12/截屏2021-12-25-20.33.43.png" alt="" class="wp-image-8805" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-20.33.43.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-25-20.33.43-300x188.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-20.33.43-1024x640.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-25-20.33.43-768x480.png 768w, /wp-content/uploads/2021/12/截屏2021-12-25-20.33.43-1536x960.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-25-20.33.43-2048x1280.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /></a></figure>



<p>.htaccess</p>



<pre class="wp-block-code"><code>&lt;IfModule mod_rewrite.c&gt;  
    &lt;IfModule mod_negotiation.c&gt;  
        Options +FollowSymLinks  
    &lt;/IfModule&gt;  
  
    RewriteEngine On  
  
    # Redirect Trailing Slashes If Not A Folder...  
    RewriteCond %{REQUEST_FILENAME} !-d  
    RewriteRule ^(.*)/$ /$1 &#91;L,R=301]  
  
    # Handle Front Controller...  
    RewriteCond %{REQUEST_FILENAME} !-d  
    RewriteCond %{REQUEST_FILENAME} !-f  
    RewriteRule ^ index.php &#91;L]  
  
    # Handle Authorization Header  
    RewriteCond %{HTTP:Authorization} .  
    RewriteRule .* - &#91;E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]  
&lt;/IfModule&gt;  </code></pre>



<p><strong>5.laravel-modules安装</strong></p>



<p>Larvel-modules会在项目目录下生成modules目录，不会更改框架原有结构，方便后续框架升级，开发代码直接写在modules目录下。</p>



<p>5.1.首先在 Laravel 项目根目录下使用 Composer 安装该扩展包。</p>



<p><br>composer require nwidart/laravel-modules</p>



<p><br>5.2.你可以通过运行如下命令来发布配置文件。</p>



<p><br>php artisan vendor:publish &#8211;provider=&#8221;Nwidart\Modules\LaravelModulesServiceProvider&#8221;</p>



<p>5.3.通过如下命令生成应用的第一个模块。</p>



<p><br>php artisan module:make Admin</p>



<p><br>5.4.要让模块目录中定义的类可以自动加载，需要配置根目录下的composer.json。</p>



<pre class="wp-block-code"><code>{
  "autoload": {
    "psr-4": {
      "App\\": "app/",
      "Modules\\": "Modules/"
    }
  }
}
</code></pre>



<p>5.5.配置完成后运行以下命令让修改生效。</p>



<p><br>composer dump-autoload</p>



<p>5.6.执行域名加模块名（例如：<a href="/goto/o5nf" rel="nofollow">http://demo:8888/admin</a><a rel="noreferrer noopener" href="/goto/74qp" rel="nofollow" target="_blank">）</a></p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.14.47.png"><img loading="lazy" decoding="async" width="1300" height="272" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.14.47.png" alt="" class="wp-image-8821" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.14.47.png 1300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.14.47-300x63.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.14.47-1024x214.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-12.14.47-768x161.png 768w" sizes="(max-width: 1300px) 100vw, 1300px" /></a><figcaption><strong>6.laravel8自动生成api文档</strong></figcaption></figure>



<p><a href="/goto/q8h6" data-type="URL" data-id="https://blog.csdn.net/JianShengShuaiest/article/details/120357911" target="_blank" rel="nofollow noreferrer noopener">laravel8自动生成api文档</a></p>



<p><a href="/goto/38a0" data-type="URL" data-id="https://www.jianshu.com/p/56c25d9bb880" target="_blank" rel="nofollow noreferrer noopener">Swagger 使用教程</a></p>



<p><a rel="noreferrer noopener" href="/goto/uhmv" rel="nofollow" data-type="URL" data-id="https://wxiangqian.blog.csdn.net/article/details/81866873" target="_blank">Swagger生成api接口文档</a></p>



<p>添加配置：</p>



<p>路径：resources/views/vendor/l5-swagger/index.blade.php</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-17.55.53.png"><img loading="lazy" decoding="async" width="816" height="256" src="/wp-content/uploads/2021/12/截屏2021-12-25-17.55.53.png" alt="" class="wp-image-8781" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-17.55.53.png 816w, /wp-content/uploads/2021/12/截屏2021-12-25-17.55.53-300x94.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-17.55.53-768x241.png 768w" sizes="(max-width: 816px) 100vw, 816px" /></a></figure>



<p>添加：deepLinking: true</p>



<p></p>



<p>修改默认模块</p>



<p>路径：config/l5-swagger.php</p>



<p>将 <em>base_path(&#8216;app&#8217;),  </em>更改为 base_path(&#8216;Modules&#8217;),</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-17.59.12.png"><img loading="lazy" decoding="async" width="1540" height="386" src="/wp-content/uploads/2021/12/截屏2021-12-25-17.59.12.png" alt="" class="wp-image-8783" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-17.59.12.png 1540w, /wp-content/uploads/2021/12/截屏2021-12-25-17.59.12-300x75.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-17.59.12-1024x257.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-25-17.59.12-768x192.png 768w, /wp-content/uploads/2021/12/截屏2021-12-25-17.59.12-1536x385.png 1536w" sizes="(max-width: 1540px) 100vw, 1540px" /></a></figure>



<pre class="wp-block-code"><code>php artisan l5-swagger:generate</code></pre>



<p>最终效果：</p>



<figure class="wp-block-image size-full is-resized"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1.png"><img loading="lazy" decoding="async" src="/wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1.png" alt="" class="wp-image-8782" width="840" height="448" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1-300x160.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1-1024x546.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1-768x410.png 768w, /wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1-1536x819.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-25-17.53.09-1-2048x1092.png 2048w" sizes="(max-width: 840px) 100vw, 840px" /></a></figure>



<p><strong>7.laravel数据迁移加注释</strong></p>



<p>默认laravel是没有带添加表注释组件的，这里需要安装zedisdog/laravel-schema-extend包<br>该组件包要求使用大于等于5.0版本的laravel</p>



<p>1.拉取组件<br></p>



<pre class="wp-block-code"><code>composer require zedisdog/laravel-schema-extend
</code></pre>



<p>2.申明依赖 （修改config-&gt;app.php-&gt;aliases）<br></p>



<pre class="wp-block-code"><code>'aliases' =&gt; &#91;
    ...
    // 'Schema' =&gt; Illuminate\Support\Facades\Schema::class,
    'Schema'    =&gt; Jialeo\LaravelSchemaExtend\Schema::class,

],
</code></pre>



<p>3.使用（默认创建的migration文件对应的“Schema”还是引用的laravel自带的，需要修改为该组件包的引用）<br></p>



<pre class="wp-block-code"><code> //use Illuminate\\Support\\Facades\\Schema;
 use Jialeo\\LaravelSchemaExtend\\Schema;
Schema::create('users', function (Blueprint $table) {
$table-&gt;comment = '用户表';
 });</code></pre>



<p><strong>8.JWT用户验证</strong></p>



<pre class="wp-block-code"><code>1.安装 jwt-auth。
composer require tymon/jwt-auth 1.*@rc
或者
composer require tymon/jwt-auth:^1.0.2

2.将服务提供程序添加到配置文件中的providers数组，config/app.php如下所示：
'providers' =&gt; &#91;
        ...
        Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
    ]

3.运行以下命令以发布程序包配置文件：
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

4.生成加密密钥:
php artisan jwt:secret

5.修改 config/auth.php
'guards'  =&gt;  &#91;
        'auth_admin' =&gt; &#91;
            'driver' =&gt; 'jwt',
            'provider' =&gt; 'auth_admins'
        ]
    ],
'providers' =&gt; &#91;
        'auth_admins' =&gt; &#91;
            'driver' =&gt; 'eloquent',
            'model' =&gt; Modules\Admin\Models\AuthAdmin::class,
        ]
    ],
6.创建模型
&lt;?php
namespace Modules\Admin\Models;
use DateTimeInterface;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class AuthAdmin extends Authenticatable implements JWTSubject
{
    use Notifiable;
    protected $guard = 'auth_admin';
    protected $hidden = &#91;
        'password'
    ];
    /**
     * @name jwt标识
     * @description
     * @author Winston
     * @date 2021/12/25 3:11
     **/
    public function getJWTIdentifier()
    {
        return $this-&gt;getKey();
    }
    /**
     * @name jwt自定义声明
     * @description
     * @author Winston
     * @date 2021/12/25 3:11
     **/
    public function getJWTCustomClaims()
    {
        return &#91;];
    }
    /**
     * @name 更新时间为null时返回
     * @description
     * @author Winston
     * @date 2021/12/25 3:11
     **/
    public function getUpdatedAtAttribute($value)
    {
        return $value?$value:'';
    }
    /**
     * @name  关联权限组表   多对一
     * @description
     * @author Winston
     * @date 2021/12/25 3:12
     **/
    public function auth_groups()
    {
        return $this-&gt;belongsTo('Modules\Admin\Models\AuthGroup','group_id','id');
    }
    /**
     * @name  关联平台项目表   多对一
     * @description
     * @author Winston
     * @date 2021/12/25 3:12
     **/
    public function auth_projects()
    {
        return $this-&gt;belongsTo('Modules\Admin\Models\AuthProject','project_id','id');
    }
    /**
     * @name 时间格式传唤
     * @description
     * @author Winston
     * @date 2021/12/25 16:15
     **/
    protected function serializeDate(DateTimeInterface $date)
    {
        return $date-&gt;format('Y-m-d H:i:s');
    }
}
7.创建token的Services
&lt;?php
/**
 * @Name 管理员信息服务
 * @Description
 * @Auther Winston
 * @Date 2021/12/25 17:10
 */
namespace Modules\Admin\Services\auth;
use Modules\Admin\Services\BaseApiService;
use Modules\Common\Exceptions\ApiException;
use Modules\Common\Exceptions\MessageData;
use Modules\Common\Exceptions\StatusData;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Tymon\JWTAuth\Facades\JWTAuth;

class TokenService extends BaseApiService
{
    /**
     * @name 设置token 生成机制
     * @description
     * @author Winston
     * @date 2021/12/25 17:23
     * @return JSON
     **/
    public function __construct()
    {
        \Config::set('auth.defaults.guard', 'auth_admin');
        \Config::set('jwt.ttl', 60);
    }
    /**
     * @name 设置token
     * @description
     * @author Winston
     * @date 2021/12/25 17:24
     * @param data  Array 用户信息
     * @param data.username String 账号
     * @param data.password String 密码$
     * @return JSON | Array
     **/
    public function setToken($data){
        if (! $token = JWTAuth::attempt($data)){
            $this-&gt;apiError('token生成失败');
        }
        return $this-&gt;respondWithToken($token);
    }
    /**
     * @name 刷新token
     * @description
     * @author Winston
     * @date 2021/12/25 17:48
     * @return JSON
     **/
    public function refreshToken()
    {
        try {
            $old_token = JWTAuth::getToken();
            $token = JWTAuth::refresh($old_token);
        }catch (TokenBlacklistedException $e) {
            // 这个时候是老的token被拉到黑名单了
            throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_BLACK,'message'=&gt;MessageData::TOKEN_ERROR_BLACK]);
        }
        return $this-&gt;apiSuccess('', $this-&gt;respondWithToken($token));
    }
    /**
     * @name 管理员信息
     * @description
     * @author Winston
     * @date 2021/12/25 19:11
     * @return Array
     **/
    public function my():Object
    {
        return JWTAuth::parseToken()-&gt;touser();
    }
    /**
     * @name
     * @description
     * @author Winston
     * @date 2021/12/25 9:53
     * @method  GET
     * @param
     * @return JSON
     **/
    public function info()
    {
        $data = $this-&gt;my();
        return $this-&gt;apiSuccess('',&#91;'username'=&gt;$data&#91;'username']]);
    }
    /**
     * @name 退出登录
     * @description
     * @author Winston
     * @date 2021/12/25 19:12
     * @return JSON
     **/
    public function logout()
    {
        JWTAuth::parseToken()-&gt;invalidate();
        return $this-&gt;apiSuccess('退出成功！');
    }

    /**
     * @name 组合token数据
     * @description
     * @author Winston
     * @date 2021/12/25 17:47
     * @return Array
     **/
    protected function respondWithToken($token):Array
    {
        return &#91;
            'token' =&gt; $token,
            'token_type' =&gt; 'bearer',
            'expires_in' =&gt; JWTAuth::factory()-&gt;getTTL() * 60
        ];
    }
}
8.创建登录Services
&lt;?php
/**
 * @Name 用户登录服务
 * @Description
 * @Auther Winston
 * @Date 2021/12/25 16:50
 */
namespace Modules\Admin\Services\auth;
use Modules\Admin\Services\BaseApiService;
use Modules\Admin\Models\AuthAdmin as AuthAdminModel;
class LoginService extends BaseApiService
{
    /**
     * @name 用户登录
     * @description
     * @author Winston
     * @date 2021/12/25 16:53
     * @param data  Array 用户信息
     * @param data.username String 账号
     * @param data.password String 密码
     * @return JSON
     **/
    public function login(array $data){
        if (true == \Auth::guard('auth_admin')-&gt;attempt($data)) {
            $userInfo = AuthAdminModel::where(&#91;'username'=&gt;$data&#91;'username']])-&gt;select('id','username')-&gt;first();
            if($userInfo){
                $user_info = $userInfo-&gt;toArray();
                $user_info&#91;'password'] = $data&#91;'password'];
                $token = (new TokenService())-&gt;setToken($user_info);
                return $this-&gt;apiSuccess('登录成功！',$token);
            }
        }
        $this-&gt;apiError('账号或密码错误！');
    }
}
9.创建中间件
&lt;?php
// +----------------------------------------------------------------------
// | Name: 管理系统 &#91; 为了快速搭建软件应用而生的，希望能够帮助到大家提高开发效率。 ]
// +----------------------------------------------------------------------
// | Copyright: (c) 2020~2021 / All rights reserved.
// +----------------------------------------------------------------------
// | Licensed: 这是一个自由软件，允许对程序代码进行修改，但希望您留下原有的注释。
// +----------------------------------------------------------------------
// | Author: Winston &lt;liyouran@live.com&gt;
// +----------------------------------------------------------------------
// | Version: V1
// +----------------------------------------------------------------------

/**
 * @Name  后台权限验证中间件
 * @Description
 * @Auther Winston
 * @Date 2021/12/25 13:37
 */

namespace Modules\Admin\Http\Middleware;

use Closure;
use Modules\Admin\Services\log\OperationLogService;
use Modules\Common\Exceptions\ApiException;
use Illuminate\Http\Request;
use Modules\Common\Exceptions\MessageData;
use Modules\Common\Exceptions\StatusData;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use JWTAuth;
use Modules\Admin\Models\Admin as AdminModel;
use Modules\Admin\Models\AuthGroup as AuthGroupModel;
use Modules\Admin\Models\AuthRule as AuthRuleModel;
class AdminApiAuth
{

    public function handle($request, Closure $next)
    {
        \Config::set('auth.defaults.guard', 'auth_admin');
        \Config::set('jwt.ttl', 60);
        $route_data = $request-&gt;route();
        $url = str_replace($route_data-&gt;getAction()&#91;'prefix'] . '/',"",$route_data-&gt;uri);
        $url_arr = &#91;'auth/login/login','auth/index/getMain','auth/index/refreshToken'];
        $api_key = $request-&gt;header('apikey');
        if($api_key != config('admin.api_key')){
            throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_KEY,'message'=&gt;MessageData::TOKEN_ERROR_KEY]);
            return $next();
        }
        if(in_array($url,$url_arr)){
            return $next($request);
        }
        try {
            if (! $user = JWTAuth::parseToken()-&gt;authenticate()) {  //获取到用户数据，并赋值给$user   'msg' =&gt; '用户不存在'
                throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_SET,'message'=&gt;MessageData::TOKEN_ERROR_SET]);
                return $next();
            }

        }catch (TokenBlacklistedException $e) {
            //token无效
            if(in_array($url,&#91;'auth/index/logout'])){
                return $next($request);
            }
            // 这个时候是老的token被拉到黑名单了
            throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_BLACK,'message'=&gt;MessageData::TOKEN_ERROR_BLACK]);
            return $next();
        } catch (TokenExpiredException $e) {
            //token无效
            if(in_array($url,&#91;'auth/index/logout'])){
                return $next($request);
            }
            //token已过期
            throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_EXPIRED,'message'=&gt;MessageData::TOKEN_ERROR_EXPIRED]);
            return $next();
        } catch (TokenInvalidException $e) {
            //token无效
            if(!in_array($url,&#91;'auth/index/refresh','auth/index/logout'])){
                throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_JWT,'message'=&gt;MessageData::TOKEN_ERROR_JWT]);
            }
            return $next();
        } catch (JWTException $e) {
            //'缺少token'
            throw new ApiException(&#91;'status'=&gt;StatusData::TOKEN_ERROR_JTB,'message'=&gt;MessageData::TOKEN_ERROR_JTB]);
            return $next();
        }
        // 写入日志
        (new OperationLogService())-&gt;store($user&#91;'id']);
//        if(!in_array($url,&#91;'auth/index/refresh','auth/index/logout'])){
//            if($user&#91;'id'] != 1 &amp;&amp; $id = AuthRuleModel::where(&#91;'href'=&gt;$url])-&gt;value('id')){
//                $rules = AuthGroupModel::where(&#91;'id'=&gt;$user&#91;'group_id']])-&gt;value('rules');
//                if(!in_array($id,explode('|',$rules))){
//                    throw new ApiException(&#91;'code'=&gt;6781,'msg'=&gt;'您没有权限！']);
//                }
//            }
//        }
        return $next($request);
    }
}
10.laravel登陆模块Demo

<meta charset="utf-8">10.1.修改config/auth.php
增加guards、providers

    'guards' =&gt; &#91;
        'web' =&gt; &#91;
            'driver' =&gt; 'session',
            'provider' =&gt; 'users',
        ],

        'api' =&gt; &#91;
            'driver' =&gt; 'token',
            'provider' =&gt; 'users',
            'hash' =&gt; false,
        ],
        'auth_admin' =&gt; &#91;
            'driver' =&gt; 'jwt',
            'provider' =&gt; 'auth_admins'
        ]
    ],

    'providers' =&gt; &#91;
        'users' =&gt; &#91;
            'driver' =&gt; 'eloquent',
            'model' =&gt; App\Models\User::class,
        ],
        'auth_admins' =&gt; &#91;
            'driver' =&gt; 'eloquent',
            'model' =&gt; Modules\Admin\Models\AuthAdmin::class,
        ]
    ],

<meta charset="utf-8">10.2.增加中间件
\Modules\Admin\Http\Middleware\AdminApiAuth

<meta charset="utf-8">10.3.app\Http\Kernel.php $routeMiddleware中增加中间件
'AdminApiAuth'=&gt; \Modules\Admin\Http\Middleware\AdminApiAuth::class,

<meta charset="utf-8">10.4.Modules\Admin\Config\config.php 定义api_key

return &#91;
'name' =&gt; 'Admin',
'api_key'=&gt;'123456',
'update_pwd'=&gt;'123456',
];

10.5编写基础控制器
&lt;?php
// +----------------------------------------------------------------------
// | Name: 管理系统 &#91; 为了快速搭建软件应用而生的，希望能够帮助到大家提高开发效率。 ]
// +----------------------------------------------------------------------
// | Copyright: (c) 2021~2022 / All rights reserved.
// +----------------------------------------------------------------------
// | Licensed: 这是一个自由软件，允许对程序代码进行修改，但希望您留下原有的注释。
// +----------------------------------------------------------------------
// | Author: Winston &lt;liyouran@live.com&gt;
// +----------------------------------------------------------------------
// | Version: V1
// +----------------------------------------------------------------------

/**
 * @Name 当前模块控制器基类
 * @Description
 * @Auther Winston
 * @Date 2021/12/26 13:10
 */

namespace Modules\Admin\Http\Controllers\v1;


use Modules\Common\Controllers\BaseController;

class BaseApiController extends BaseController
{
    public function __construct(){
        parent::__construct();
    }
}


<meta charset="utf-8">10.6.编写登陆controller
&lt;?php
// +----------------------------------------------------------------------
// | Name: 管理系统 &#91; 为了快速搭建软件应用而生的，希望能够帮助到大家提高开发效率。 ]
// +----------------------------------------------------------------------
// | Copyright: (c) 2021~2022 / All rights reserved.
// +----------------------------------------------------------------------
// | Licensed: 这是一个自由软件，允许对程序代码进行修改，但希望您留下原有的注释。
// +----------------------------------------------------------------------
// | Author: Winston &lt;liyouran@live.com&gt;
// +----------------------------------------------------------------------
// | Version: V1
// +----------------------------------------------------------------------

/**
 * @Name 用户登录
 * @Description
 * @Auther Winston
 * @Date 2021/12/26 13:10
 */

namespace Modules\Admin\Http\Controllers\v1;


use Modules\Admin\Http\Requests\LoginRequest;
use Modules\Admin\Services\auth\LoginService;
class LoginController extends BaseApiController
{
    /**
     * @name 用户登录
     * @description
     * @author Winston
     * @date 2021/12/26 13:10
     * @method  POST
     * @param username String 账号
     * @param password String 密码
     * @return JSON
     **/
    public function login(LoginRequest $request)
    {
        return (new LoginService())-&gt;login($request-&gt;only(&#91;'username','password']));
    }
}

<meta charset="utf-8">10.7.编写登陆request
&lt;?php

namespace Modules\Admin\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class LoginRequest extends FormRequest
{
	/**
     * php artisan module:make-request LoginRequest AuthAdmin
     */


	 /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return &#91;
			'username' =&gt; 'required',
            'password'  =&gt; 'required'
        ];
    }
	public function messages(){
		return &#91;
			'username.required' =&gt; '请输入账号！',
			'password.required' =&gt; '请输入密码！',
		];
	}

}


<meta charset="utf-8">10.8.编写api路由
&lt;?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')-&gt;get('/admin', function (Request $request) {
    return $request-&gt;user();
});

Route::group(&#91;"prefix"=&gt;"v1/admin","middleware"=&gt;"AdminApiAuth"],function (){
    //登录
    Route::post('login/login', 'v1\LoginController@login');
});


<meta charset="utf-8">10.9.修改config/databases.php
增加表前缀：prefix =&gt; 'lv_',

<meta charset="utf-8">10.10.修改.env中数据库连接配置
DB_PORT:8889,
DB_DATABASES:laravel,
DB_USERNAME=root,
DB_PASSWORD=root,

<meta charset="utf-8">10.11.连接数据库，创建用户表及数据初始化
USE laravel;
DROP TABLE IF EXISTS `lv_auth_admins`;
CREATE TABLE `lv_auth_admins` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '管理员ID',
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
`phone` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '手机号',
`username` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '账号',
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '密码',
`group_id` int(11) DEFAULT NULL COMMENT '权限组ID',
`project_id` int(11) DEFAULT NULL COMMENT '项目ID',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:0=禁用,1=启用',
`created_at` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `lv_auth_admins_username_unique` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='管理员表';

INSERT INTO `lv_auth_admins` VALUES (1,'','','admin','$2y$10$gddj.QV7l7OP3I2MpgM9COcCKCBM8SMPq.xe/JrqkOXY3DlnozTP.',1,1,1,'2021-12-26 14:56:02','2021-12-26 14:56:02');
INSERT INTO `lv_auth_admins` VALUES (2,'winston','','winston','$2y$10$NhdagpIFbxK2zAVFeCFEa.wUrtKv.2o4aG4ZZ5W3yYB9epkx/Xm9y',2,1,1,'2021-12-26 14:56:02','2021-12-26 14:56:02');

<meta charset="utf-8">10.12.php artisan l5-swagger:generate更新接口文档

<meta charset="utf-8">10.13.打开http://域名/api/documentation 查看文档及进行测试</code></pre>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.18.png"><img loading="lazy" decoding="async" width="2880" height="1660" src="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.18.png" alt="" class="wp-image-8826" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.18.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.18-300x173.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.18-1024x590.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.18-768x443.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.18-1536x885.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.18-2048x1180.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /></a></figure>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.46.png"><img loading="lazy" decoding="async" width="2880" height="1484" src="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.46.png" alt="" class="wp-image-8827" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.46.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.46-300x155.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.46-1024x528.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.46-768x396.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.46-1536x791.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.46-2048x1055.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /></a></figure>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.59.png"><img loading="lazy" decoding="async" width="2880" height="354" src="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.59.png" alt="" class="wp-image-8828" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-15.26.59.png 2880w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.59-300x37.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.59-1024x126.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.59-768x94.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.59-1536x189.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-26-15.26.59-2048x252.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /></a></figure>



<p><strong>9.laravel使用redis</strong></p>



<p>首先确认服务器已经安装redis服务,php安装了redis扩展.<br>因为我们在laravel的项目中需要下载laravel的redis扩展</p>



<pre class="wp-block-code"><code>composer require predis/predis

1.打开config/database.php。在redis配置项中增加session的连接</code></pre>



<pre class="wp-block-code"><code>'session' =&gt; &#91;
            'host' =&gt; env('REDIS_HOST', '127.0.0.1'),
            'password' =&gt; env('REDIS_PASSWORD', null),
            'port' =&gt; env('REDIS_PORT', 6379),
            'database' =&gt; 10,
 ],
</code></pre>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.03.37.png"><img loading="lazy" decoding="async" width="2006" height="1348" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.03.37.png" alt="" class="wp-image-8813" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.03.37.png 2006w, /wp-content/uploads/2021/12/截屏2021-12-26-12.03.37-300x202.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.03.37-1024x688.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-12.03.37-768x516.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-12.03.37-1536x1032.png 1536w" sizes="(max-width: 2006px) 100vw, 2006px" /></a><figcaption>2.打开config/session.php ,修改driver配置项,将默认的&#8217;file&#8217;改为&#8217;redis&#8217;；connection配置项填入第一步中配置的redis连接名&#8217;session&#8217;</figcaption></figure>



<pre class="wp-block-code"><code>'driver' =&gt; env('SESSION_DRIVER','redis'),
'connection' =&gt; 'session',
</code></pre>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.05.02.png"><img loading="lazy" decoding="async" width="932" height="152" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.05.02.png" alt="" class="wp-image-8815" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.05.02.png 932w, /wp-content/uploads/2021/12/截屏2021-12-26-12.05.02-300x49.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.05.02-768x125.png 768w" sizes="(max-width: 932px) 100vw, 932px" /></a></figure>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.05.12.png"><img loading="lazy" decoding="async" width="854" height="104" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.05.12.png" alt="" class="wp-image-8816" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.05.12.png 854w, /wp-content/uploads/2021/12/截屏2021-12-26-12.05.12-300x37.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.05.12-768x94.png 768w" sizes="(max-width: 854px) 100vw, 854px" /></a><figcaption>3.修改.env文件,使用redis存取sessoin</figcaption></figure>



<pre class="wp-block-code"><code>SESSION_DRIVER=redis
</code></pre>



<h1 class="wp-block-heading">phpstorm相关配置</h1>



<p>1.phpstorm设置ctrl+鼠标滚轮更改字体大小。</p>



<p>Flie-&gt;Settings-&gt;Editor-&gt;General</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.06.12.png"><img loading="lazy" decoding="async" width="1960" height="1410" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.06.12.png" alt="" class="wp-image-8817" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.06.12.png 1960w, /wp-content/uploads/2021/12/截屏2021-12-26-12.06.12-300x216.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.06.12-1024x737.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-12.06.12-768x552.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-12.06.12-1536x1105.png 1536w" sizes="(max-width: 1960px) 100vw, 1960px" /></a></figure>



<p>Flie-&gt;Settings-&gt;File Encodings</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.07.19.png"><img loading="lazy" decoding="async" width="1952" height="1406" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.07.19.png" alt="" class="wp-image-8818" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.07.19.png 1952w, /wp-content/uploads/2021/12/截屏2021-12-26-12.07.19-300x216.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.07.19-1024x738.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-12.07.19-768x553.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-12.07.19-1536x1106.png 1536w" sizes="(max-width: 1952px) 100vw, 1952px" /></a></figure>



<p>File-&gt;setting&#8211;&gt;Editor&#8211;&gt;File and Code Templates</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-26-12.08.59.png"><img loading="lazy" decoding="async" width="1950" height="1410" src="/wp-content/uploads/2021/12/截屏2021-12-26-12.08.59.png" alt="" class="wp-image-8819" srcset="/wp-content/uploads/2021/12/截屏2021-12-26-12.08.59.png 1950w, /wp-content/uploads/2021/12/截屏2021-12-26-12.08.59-300x217.png 300w, /wp-content/uploads/2021/12/截屏2021-12-26-12.08.59-1024x740.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-26-12.08.59-768x555.png 768w, /wp-content/uploads/2021/12/截屏2021-12-26-12.08.59-1536x1111.png 1536w" sizes="(max-width: 1950px) 100vw, 1950px" /></a></figure>



<pre class="wp-block-code"><code><meta charset="utf-8">// +----------------------------------------------------------------------
// | Name: 管理系统 &#91; 为了快速搭建软件应用而生的，希望能够帮助到大家提高开发效率。 ]
// +----------------------------------------------------------------------
// | Copyright: (c) 2020~2021 / All rights reserved.
// +----------------------------------------------------------------------
// | Licensed: 这是一个自由软件，允许对程序代码进行修改，但希望您留下原有的注释。
// +----------------------------------------------------------------------
// | Author: Winston &lt;liyouran@live.com&gt;
// +----------------------------------------------------------------------
// | Version: V1
// +----------------------------------------------------------------------

/**
 * @Name   
 * @Description
 * @Auther Winston
 * @Date ${DATE} ${HOUR}:${MINUTE}
 */

4.设置方法注释。

File-&gt;setting--&gt;Editor--&gt;live Templates
点击右边加号添加一个Templates Group -&gt; 然后选中添加的Group再次点击加号添加Live Templates，之后点击Edit variables，配置variables。</code></pre>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2021/12/截屏2021-12-25-18.35.49.png"><img loading="lazy" decoding="async" width="2796" height="1652" src="/wp-content/uploads/2021/12/截屏2021-12-25-18.35.49.png" alt="" class="wp-image-8793" srcset="/wp-content/uploads/2021/12/截屏2021-12-25-18.35.49.png 2796w, /wp-content/uploads/2021/12/截屏2021-12-25-18.35.49-300x177.png 300w, /wp-content/uploads/2021/12/截屏2021-12-25-18.35.49-1024x605.png 1024w, /wp-content/uploads/2021/12/截屏2021-12-25-18.35.49-768x454.png 768w, /wp-content/uploads/2021/12/截屏2021-12-25-18.35.49-1536x908.png 1536w, /wp-content/uploads/2021/12/截屏2021-12-25-18.35.49-2048x1210.png 2048w" sizes="(max-width: 2796px) 100vw, 2796px" /></a></figure>



<pre class="wp-block-code"><code>/**
 * @Name 
 * @Author<meta charset="utf-8"> Winston
 * @Description 
 * @Date $date$ $time$ 
 * @Method  GET	
 * @Param 
 * @Return JSON
 **/</code></pre>



<h1 class="wp-block-heading">NUXT文档</h1>



<h2 class="wp-block-heading">nuxt安装</h2>



<p>确保安装了 npx（npx 在 NPM 版本 5.2.0 默认安装了）：</p>



<p>npx create-nuxt-app &lt;项目名&gt;<br>或者用 yarn ：</p>



<p>yarn create nuxt-app &lt;项目名&gt;<br>它会让你进行一些选择:</p>



<p>在集成的服务器端框架之间进行选择:<br>None (Nuxt 默认服务器)<br>Express<br>Koa<br>Hapi<br>Feathers<br>Micro<br>Fastify<br>Adonis(WIP)<br>选择您喜欢的 UI 框架:<br>None (无)<br>Bootstrap<br>Vuetify<br>Bulma<br>Tailwind<br>Element UI<br>Ant Design Vue<br>Buefy<br>iView<br>Tachyons<br>选择您喜欢的测试框架:<br>None (随意添加一个)<br>Jest<br>AVA<br>选择你想要的 Nuxt 模式 (UniversalorSPA)<br>添加axios module以轻松地将 HTTP 请求发送到您的应用程序中。<br>添加EsLint以在保存时代码规范和错误检查您的代码。<br>添加Prettier以在保存时格式化/美化您的代码。<br>当运行完时，它将安装所有依赖项，因此下一步是启动项目:</p>



<p>$ cd<br>$ npm run dev</p>



<p>应用现在运行在 http://localhost:3000/ 上运行。</p>



<p>注意：Nuxt.js 会监听pages目录中的文件更改，因此在添加新页面时无需重新启动应用程序。</p>



<p>了解模板项目的目录结构：目录结构。</p>



<p>从头开始新建项目<br>如果不使用 Nuxt.js 提供的 starter 模板，我们也可以从头开始新建一个 Nuxt.js 应用项目，过程非常简单，只需要1 个文件和 1 个目录。如下所示：</p>



<p>$ mkdir &lt;项目名&gt;<br>$ cd &lt;项目名&gt;</p>



<p><strong>提示:</strong>将&lt;项目名&gt;替换成为你想创建的实际项目名。</p>



<p>新建 package.json 文件<br>package.json文件用来设定如何运行nuxt：</p>



<p>{<br>&#8220;name&#8221;: &#8220;my-app&#8221;,<br>&#8220;scripts&#8221;: {<br>&#8220;dev&#8221;: &#8220;nuxt&#8221;<br>}<br>}</p>



<p>上面的配置使得我们可以通过运行npm run dev来运行nuxt。</p>



<p>安装nuxt<br>一旦package.json创建好， 可以通过以下 npm 命令将nuxt安装至项目中：</p>



<p>npm install &#8211;save nuxt</p>



<p>pages 目录<br>Nuxt.js 会依据pages目录中的所有*.vue文件生成应用的路由配置。</p>



<p>创建pages目录：</p>



<p>mkdir pages</p>



<p>创建我们的第一个页面pages/index.vue：</p>



<p><br>然后启动项目：</p>



<p>$ npm run dev</p>



<p></p>



<h2 class="wp-block-heading">nuxt的生命周期</h2>



<p>服务端生命周期<br>服务器初始化nuxtServerInit<br>创建store/index.js</p>



<p>export const actions = {<br>nuxtServerInit(store,context){<br>console.log(&#8216;nuxtServerInit&#8217;,store,context)<br>}<br>}<br>中间件运行middleware<br>在nuxt.config.js中定义中间件</p>



<p>router:{<br>middleware:&#8217;auth&#8217;<br>}<br>创建中间件文件middleware/auth.js</p>



<p>export default function({store,route,redirect,params,query,req,res}) {<br>console.log(&#8216;middleware&#8217;)<br>}<br>定义在layouts/default.vue中</p>



<p>export default{<br>// middleware:&#8217;auth&#8217; ,<br>middleware(){<br>console.log(&#8216;middleware&#8217;)<br>}<br>}<br>定义在pages/index.vue中</p>



<p>export default{<br>// middleware:&#8217;auth&#8217; ,<br>middleware(){<br>console.log(&#8216;middleware&#8217;)<br>}<br>}<br>验证参数validate</p>



<p>export default{<br>validate(context){<br>console.log(&#8216;validate&#8217;)<br>return true<br>}<br>}<br>异步数据处理asyncData、 fetch</p>



<p>export default{<br>asyncData(context){<br>console.log(&#8216;asyncData&#8217;)<br>return {<br>a:666<br>}<br>},<br>fetch(context){<br>console.log(&#8216;fetch&#8217;)<br>}<br>}<br>开始客户端渲染Render</p>



<p>Vue生命周期 SSR CSR<br>组件创建前beforeCreated</p>



<p>export default{<br>beforeCreated(){<br>console.log(&#8216;beforeCreated&#8217;)<br>}<br>}<br>组件创建后created</p>



<p>export default{<br>created(){<br>console.log(&#8216;created&#8217;)<br>}<br>}<br>运行在客户端<br>组件加载前 beforeMount<br>组件加载完毕 mounted<br>组件更新前 beforeUpdate<br>组件更新完毕 updated<br>组件卸载前 beforeDestroy<br>组件卸载后 destroyed</p>



<h2 class="wp-block-heading">nuxt安装element-ui</h2>



<p>1.安装element-ui<br>npm install element-ui &#8211;save &#8211;registry=https://registry.npm.taobao.org/<br>2.创建文件<br>在项目的根目录下的plugins下创建element-ui.js文件</p>



<p>import Vue from &#8220;vue&#8221;;<br>import ElementUI from &#8220;element-ui&#8221;<br>Vue.use(ElementUI)</p>



<p>import Button from &#8220;element-ui&#8221;<br>Vue.use(Button)<br>3.引入文件<br>在nuxt.config.js中修改如下：</p>



<p>// Global CSS: https://go.nuxtjs.dev/config-css<br>css: [ &#8220;element-ui/lib/theme-chalk/index.css&#8221;],</p>



<p>// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins<br>plugins: [{ src: &#8220;~plugins/element-ui&#8221;,ssr:true,mode:&#8217;server&#8217;//client }],<br>build:{<br>transpile:[&#8216;/^element-ui/&#8217;]<br>}</p>



<h2 class="wp-block-heading">vue监听路由</h2>



<p>watch:{<br>$route:{<br>immediate:true,<br>handler(route){</p>



<pre class="wp-block-code"><code>      }
}</code></pre>



<p>}</p>



<h2 class="wp-block-heading">vue跳转页面</h2>



<p>this.$router.push()</p>



<h2 class="wp-block-heading">Nuxt安装scss(sass)</h2>



<p>1.安装需要用到的loader</p>



<pre class="wp-block-code"><code>npm install --save-dev node-sass@4.12.0 --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
npm install --save-dev sass-loader@7.1.0  --registry=https://registry.npm.taobao.org/
</code></pre>



<p>2.使用</p>



<pre class="wp-block-code"><code>&lt;style lang="scss"&gt;//注意!这里很关键,很多配置成了不编译就是漏了lang="scss"

   @import '../assets/css/index.scss';
   @import '../assets/css/base.scss';
   @import '../assets/css/common.scss';

&lt;/style&gt;
</code></pre>



<h2 class="wp-block-heading">nuxt数据交互</h2>



<p>1.nuxt做数据交互需要依靠&nbsp;<code>@nuxtjs/axios</code><code>@nuxtjs/proxy</code></p>



<pre class="wp-block-code"><code>npm install @nuxtjs/axios  --save --registry=https://registry.npm.taobao.org/
npm install @nuxtjs/proxy --save --registry=https://registry.npm.taobao.org/
</code></pre>



<p>2.在nuxt.config.js中进行配置</p>



<pre class="wp-block-code"><code>modules:&#91;
    '@nuxtjs/axios'
]
</code></pre>



<p>3.使用<code>axios</code></p>



<pre class="wp-block-code"><code>async asyncData({$axios}){
    const res = await $axios({url:'接口'})
}
</code></pre>



<p>4.处理跨域请求， 在nuxt.config.js中进行配置</p>



<pre class="wp-block-code"><code>        axios:{
                proxy:true,//  开启跨域行为
                prefix:'/api/v1/blogApi',  //配置基本的url地址 
          },
        
        proxy:{
                '/api':{
                target:'http://www.mileduo.com/',  //  代理转发的地址
                pathRewrite:{
                // '^/api':''                // 找到地址中的api并替换成空    
                       }
                }
        
          },
</code></pre>



<p>5.定义拦截器，修改nuxt.config.js</p>



<pre class="wp-block-code"><code>plugins:&#91;
    {
        src:'~/plugins/axios',
        'ssr':true     //  服务端渲染
    }
]
</code></pre>



<p>6.书写axios.js</p>



<pre class="wp-block-code"><code>export default function({$axios,redirect,route,store}){
    // 基本配置
    $axios.defaults.timeout = 1000
    $axios.defaults.validateStatus = (status)=&gt;{
            return status &gt;= 200 &amp;&amp; status &lt; 600
    }
    // 请求拦截
    $axios.onRequest(config=&gt;{
        config.headers.token = ''
        return config
    })
    // 相应拦截
    $axios.onResponse(res\=&gt;{
        returnres.data
    })
    // 错误处理
    $axios.onError(error\=&gt;{
        return error
    })
}
</code></pre>



<p>7.Promise返回值</p>



<pre class="wp-block-code"><code>return new Promise(resolve=&gt;{

    resolve(res.data)

})


</code></pre>



<h2 class="wp-block-heading">nuxt中使用vuex</h2>



<p>1.定义</p>



<pre class="wp-block-code"><code>export const state = ()=&gt;({
    typeList : &#91;]
})
export const mutations = {
    SET_TYPE_LIST(state,typeList){
        state.typeList = typeList
    }
 }
export const actions = {
     UPDATE_TYPE_LIST({commit,state},typeList){
            commit('SET_TYPE_LIST',typeList)        
    }
}
export const getters = {
    getTypeList(state){
        return state.typeList
    }
}
</code></pre>



<p>2.使用</p>



<pre class="wp-block-code"><code>// 调用actions   异步请求
this.$store.dispatch('UPDATE_TYPE_LIST',&#91;])

// 调用mutations 
this.$store.commit('SET_TYPE_LIST',&#91;])
</code></pre>



<p>辅助函数</p>



<pre class="wp-block-code"><code> import {mapActions,mapGetters,mapState,mapMutations} from 'vuex'

methods:{
        getTypeList(){
            this.UPDATE_TYPE_LIST(&#91;])
            this.SET_TYPE_LIST(&#91;])
        },
    ...mapActions('user',&#91;'UPDATE_TYPE_LIST'])
    ...mapMutations('user',&#91;'SET_TYPE_LIST'])
},
// 计算属性
computed:{
    ..mapGetters('模块名称，根模块可以不传',&#91;'getTypeList'])
     ..mapState('模块名称，根模块可以不传',&#91;'typeList '])
}
</code></pre>



<h2 class="wp-block-heading">nuxt的token持久化存储</h2>



<p>1.安装cookie-nuiversal-nuxt</p>



<pre class="wp-block-code"><code>npm install cookie-nuiversal-nuxt --save  --registry=https://registry.npm.taobao.org/
</code></pre>



<p>2.配置nuxt.config.js</p>



<pre class="wp-block-code"><code>modules:&#91;
    'cookie-nuiversal-nuxt'
]
</code></pre>



<p>.3.使用</p>



<pre class="wp-block-code"><code>this.$cookies.set('user',&#91;])
this.$cookies.get('user')
this.$cookies.remove('user')
</code></pre>



<p>4.登录跳转</p>



<pre class="wp-block-code"><code>if(!this.$route.query.path || /login/reg/.test(this.$route.query.path)){
    this.$router.replace('/user')
}else{
    this.$router.replace(this.$route.query.path)
}
</code></pre>



<p>5.页面刷新初始化vuex</p>



<pre class="wp-block-code"><code>export const actions = {
    nuxtServerInit(store,{app:{$cookies}}){
        let user = $cookies.get('user')
        user = user?user:''
        store.commit('user/asdds')
    }
}
</code></pre>



<p>6.拦截器定义</p>



<pre class="wp-block-code"><code>$axios.onRequest(config=&gt;{
    config.headers.token = store.state.user.token 
})
</code></pre>



<h2 class="wp-block-heading">nuxt定义错误页面</h2>



<p>在layouts下创建error.vue页面，内容如下。</p>



<pre class="wp-block-code"><code>&lt;template&gt;
    &lt;div&gt;
        &lt;h1 v-if="error.statusCode"&gt;{{error.message}}&lt;/h1&gt;
        &lt;h1 v-else&gt;应用异常&lt;/h1&gt;
        &lt;el-button @click="$router.replace('/')"&gt;返回首页&lt;/el-button&gt;
    &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
    export default{
        props:&#91;'error']
    }
&lt;/script&gt;
</code></pre>



<h2 class="wp-block-heading">unxt路由跳转过度动画</h2>



<p>1.在/assert目录下建立一个page-transletion.css文件，里面包含过渡动画内容，内容如下：</p>



<pre class="wp-block-code"><code> .page-enter-active, .page-leave-active {
  transition: opacity  .5s;
  }
  .page-enter, .page-leave-active {
  opacity: 0;
  }
</code></pre>



<p>2.在nuxt.config.js中配置：</p>



<pre class="wp-block-code"><code>css: &#91;
'assets/page-transletion.css'
]</code></pre>



<h2 class="wp-block-heading">nuxt自定义loading</h2>



<p>1.修改配置</p>



<pre class="wp-block-code"><code>loading:{color:#399,height:'3px'}
</code></pre>



<pre class="wp-block-code"><code>loading:'~/components/Loading/index.vue'
</code></pre>



<p>2.编写loading组件</p>



<pre class="wp-block-code"><code>&lt;template lang="html"&gt;
  &lt;div class="loading-page" v-if="loading"&gt;
    &lt;p&gt;Loading...&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data: () =&gt; ({
    loading: false
  }),
  methods: {
    start () {
      this.loading = true
    },
    finish () {
      this.loading = false
    }
  }
}
&lt;/script&gt;

&lt;style scoped&gt;
.loading-page {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.8);
  text-align: center;
  padding-top: 200px;
  font-size: 30px;
  font-family: sans-serif;
}
&lt;/style&gt;</code></pre>



<h1 class="wp-block-heading">ZSH</h1>



<pre class="wp-block-code"><code>Last login: Sat Dec 25 13:15:03 on console
lee@MacBook-Pro ~ % composer create-project --prefer-dist laravel/laravel laraveldemo
Creating a "laravel/laravel" project at "./laraveldemo"
Installing laravel/laravel (v8.6.10)
  - Installing laravel/laravel (v8.6.10): Extracting archive
Created project in /Users/lee/laraveldemo
&gt; @php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies
Lock file operations: 110 installs, 0 updates, 0 removals
  - Locking asm89/stack-cors (v2.0.3)
  - Locking brick/math (0.9.3)
  - Locking dflydev/dot-access-data (v3.0.1)
  - Locking doctrine/inflector (2.0.4)
  - Locking doctrine/instantiator (1.4.0)
  - Locking doctrine/lexer (1.2.1)
  - Locking dragonmantank/cron-expression (v3.1.0)
  - Locking egulias/email-validator (2.1.25)
  - Locking facade/flare-client-php (1.9.1)
  - Locking facade/ignition (2.17.3)
  - Locking facade/ignition-contracts (1.0.2)
  - Locking fakerphp/faker (v1.17.0)
  - Locking filp/whoops (2.14.4)
  - Locking fruitcake/laravel-cors (v2.0.4)
  - Locking graham-campbell/result-type (v1.0.4)
  - Locking guzzlehttp/guzzle (7.4.1)
  - Locking guzzlehttp/promises (1.5.1)
  - Locking guzzlehttp/psr7 (2.1.0)
  - Locking hamcrest/hamcrest-php (v2.0.1)
  - Locking laravel/framework (v8.77.1)
  - Locking laravel/sail (v1.12.12)
  - Locking laravel/sanctum (v2.13.0)
  - Locking laravel/serializable-closure (v1.0.5)
  - Locking laravel/tinker (v2.6.3)
  - Locking league/commonmark (2.1.0)
  - Locking league/config (v1.1.1)
  - Locking league/flysystem (1.1.9)
  - Locking league/mime-type-detection (1.9.0)
  - Locking mockery/mockery (1.4.4)
  - Locking monolog/monolog (2.3.5)
  - Locking myclabs/deep-copy (1.10.2)
  - Locking nesbot/carbon (2.55.2)
  - Locking nette/schema (v1.2.2)
  - Locking nette/utils (v3.2.6)
  - Locking nikic/php-parser (v4.13.2)
  - Locking nunomaduro/collision (v5.10.0)
  - Locking opis/closure (3.6.2)
  - Locking phar-io/manifest (2.0.3)
  - Locking phar-io/version (3.1.0)
  - Locking phpdocumentor/reflection-common (2.2.0)
  - Locking phpdocumentor/reflection-docblock (5.3.0)
  - Locking phpdocumentor/type-resolver (1.5.1)
  - Locking phpoption/phpoption (1.8.1)
  - Locking phpspec/prophecy (v1.15.0)
  - Locking phpunit/php-code-coverage (9.2.10)
  - Locking phpunit/php-file-iterator (3.0.6)
  - Locking phpunit/php-invoker (3.1.1)
  - Locking phpunit/php-text-template (2.0.4)
  - Locking phpunit/php-timer (5.0.3)
  - Locking phpunit/phpunit (9.5.10)
  - Locking psr/container (1.1.2)
  - Locking psr/event-dispatcher (1.0.0)
  - Locking psr/http-client (1.0.1)
  - Locking psr/http-factory (1.0.1)
  - Locking psr/http-message (1.0.1)
  - Locking psr/log (2.0.0)
  - Locking psr/simple-cache (1.0.1)
  - Locking psy/psysh (v0.10.12)
  - Locking ralouphie/getallheaders (3.0.3)
  - Locking ramsey/collection (1.2.2)
  - Locking ramsey/uuid (4.2.3)
  - Locking sebastian/cli-parser (1.0.1)
  - Locking sebastian/code-unit (1.0.8)
  - Locking sebastian/code-unit-reverse-lookup (2.0.3)
  - Locking sebastian/comparator (4.0.6)
  - Locking sebastian/complexity (2.0.2)
  - Locking sebastian/diff (4.0.4)
  - Locking sebastian/environment (5.1.3)
  - Locking sebastian/exporter (4.0.4)
  - Locking sebastian/global-state (5.0.3)
  - Locking sebastian/lines-of-code (1.0.3)
  - Locking sebastian/object-enumerator (4.0.4)
  - Locking sebastian/object-reflector (2.0.4)
  - Locking sebastian/recursion-context (4.0.4)
  - Locking sebastian/resource-operations (3.0.3)
  - Locking sebastian/type (2.3.4)
  - Locking sebastian/version (3.0.2)
  - Locking swiftmailer/swiftmailer (v6.3.0)
  - Locking symfony/console (v5.4.1)
  - Locking symfony/css-selector (v6.0.1)
  - Locking symfony/deprecation-contracts (v3.0.0)
  - Locking symfony/error-handler (v5.4.1)
  - Locking symfony/event-dispatcher (v6.0.1)
  - Locking symfony/event-dispatcher-contracts (v3.0.0)
  - Locking symfony/finder (v5.4.0)
  - Locking symfony/http-foundation (v5.4.1)
  - Locking symfony/http-kernel (v5.4.1)
  - Locking symfony/mime (v5.4.0)
  - Locking symfony/polyfill-ctype (v1.23.0)
  - Locking symfony/polyfill-iconv (v1.23.0)
  - Locking symfony/polyfill-intl-grapheme (v1.23.1)
  - Locking symfony/polyfill-intl-idn (v1.23.0)
  - Locking symfony/polyfill-intl-normalizer (v1.23.0)
  - Locking symfony/polyfill-mbstring (v1.23.1)
  - Locking symfony/polyfill-php72 (v1.23.0)
  - Locking symfony/polyfill-php73 (v1.23.0)
  - Locking symfony/polyfill-php80 (v1.23.1)
  - Locking symfony/polyfill-php81 (v1.23.0)
  - Locking symfony/process (v5.4.0)
  - Locking symfony/routing (v5.4.0)
  - Locking symfony/service-contracts (v2.4.1)
  - Locking symfony/string (v6.0.1)
  - Locking symfony/translation (v6.0.1)
  - Locking symfony/translation-contracts (v3.0.0)
  - Locking symfony/var-dumper (v5.4.1)
  - Locking theseer/tokenizer (1.2.1)
  - Locking tijsverkoyen/css-to-inline-styles (2.2.4)
  - Locking vlucas/phpdotenv (v5.4.1)
  - Locking voku/portable-ascii (1.5.6)
  - Locking webmozart/assert (1.10.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 110 installs, 0 updates, 0 removals
  - Installing doctrine/inflector (2.0.4): Extracting archive
  - Installing doctrine/lexer (1.2.1): Extracting archive
  - Installing symfony/polyfill-ctype (v1.23.0): Extracting archive
  - Installing webmozart/assert (1.10.0): Extracting archive
  - Installing dragonmantank/cron-expression (v3.1.0): Extracting archive
  - Installing symfony/polyfill-php80 (v1.23.1): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.23.1): Extracting archive
  - Installing symfony/var-dumper (v5.4.1): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.23.1): Extracting archive
  - Installing symfony/string (v6.0.1): Extracting archive
  - Installing psr/container (1.1.2): Extracting archive
  - Installing symfony/service-contracts (v2.4.1): Extracting archive
  - Installing symfony/polyfill-php73 (v1.23.0): Extracting archive
  - Installing symfony/deprecation-contracts (v3.0.0): Extracting archive
  - Installing symfony/console (v5.4.1): Extracting archive
  - Installing psr/log (2.0.0): Extracting archive
  - Installing monolog/monolog (2.3.5): Extracting archive
  - Installing voku/portable-ascii (1.5.6): Extracting archive
  - Installing phpoption/phpoption (1.8.1): Extracting archive
  - Installing graham-campbell/result-type (v1.0.4): Extracting archive
  - Installing vlucas/phpdotenv (v5.4.1): Extracting archive
  - Installing symfony/css-selector (v6.0.1): Extracting archive
  - Installing tijsverkoyen/css-to-inline-styles (2.2.4): Extracting archive
  - Installing symfony/routing (v5.4.0): Extracting archive
  - Installing symfony/process (v5.4.0): Extracting archive
  - Installing symfony/polyfill-php72 (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-idn (v1.23.0): Extracting archive
  - Installing symfony/mime (v5.4.0): Extracting archive
  - Installing symfony/http-foundation (v5.4.1): Extracting archive
  - Installing psr/event-dispatcher (1.0.0): Extracting archive
  - Installing symfony/event-dispatcher-contracts (v3.0.0): Extracting archive
  - Installing symfony/event-dispatcher (v6.0.1): Extracting archive
  - Installing symfony/error-handler (v5.4.1): Extracting archive
  - Installing symfony/http-kernel (v5.4.1): Extracting archive
  - Installing symfony/finder (v5.4.0): Extracting archive
  - Installing symfony/polyfill-iconv (v1.23.0): Extracting archive
  - Installing egulias/email-validator (2.1.25): Extracting archive
  - Installing swiftmailer/swiftmailer (v6.3.0): Extracting archive
  - Installing symfony/polyfill-php81 (v1.23.0): Extracting archive
  - Installing ramsey/collection (1.2.2): Extracting archive
  - Installing brick/math (0.9.3): Extracting archive
  - Installing ramsey/uuid (4.2.3): Extracting archive
  - Installing psr/simple-cache (1.0.1): Extracting archive
  - Installing opis/closure (3.6.2): Extracting archive
  - Installing symfony/translation-contracts (v3.0.0): Extracting archive
  - Installing symfony/translation (v6.0.1): Extracting archive
  - Installing nesbot/carbon (2.55.2): Extracting archive
  - Installing league/mime-type-detection (1.9.0): Extracting archive
  - Installing league/flysystem (1.1.9): Extracting archive
  - Installing nette/utils (v3.2.6): Extracting archive
  - Installing nette/schema (v1.2.2): Extracting archive
  - Installing dflydev/dot-access-data (v3.0.1): Extracting archive
  - Installing league/config (v1.1.1): Extracting archive
  - Installing league/commonmark (2.1.0): Extracting archive
  - Installing laravel/serializable-closure (v1.0.5): Extracting archive
  - Installing laravel/framework (v8.77.1): Extracting archive
  - Installing facade/ignition-contracts (1.0.2): Extracting archive
  - Installing facade/flare-client-php (1.9.1): Extracting archive
  - Installing facade/ignition (2.17.3): Extracting archive
  - Installing fakerphp/faker (v1.17.0): Extracting archive
  - Installing asm89/stack-cors (v2.0.3): Extracting archive
  - Installing fruitcake/laravel-cors (v2.0.4): Extracting archive
  - Installing psr/http-message (1.0.1): Extracting archive
  - Installing psr/http-client (1.0.1): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing guzzlehttp/psr7 (2.1.0): Extracting archive
  - Installing guzzlehttp/promises (1.5.1): Extracting archive
  - Installing guzzlehttp/guzzle (7.4.1): Extracting archive
  - Installing laravel/sail (v1.12.12): Extracting archive
  - Installing laravel/sanctum (v2.13.0): Extracting archive
  - Installing nikic/php-parser (v4.13.2): Extracting archive
  - Installing psy/psysh (v0.10.12): Extracting archive
  - Installing laravel/tinker (v2.6.3): Extracting archive
  - Installing hamcrest/hamcrest-php (v2.0.1): Extracting archive
  - Installing mockery/mockery (1.4.4): Extracting archive
  - Installing filp/whoops (2.14.4): Extracting archive
  - Installing nunomaduro/collision (v5.10.0): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing phpdocumentor/type-resolver (1.5.1): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.3.0): Extracting archive
  - Installing sebastian/version (3.0.2): Extracting archive
  - Installing sebastian/type (2.3.4): Extracting archive
  - Installing sebastian/resource-operations (3.0.3): Extracting archive
  - Installing sebastian/recursion-context (4.0.4): Extracting archive
  - Installing sebastian/object-reflector (2.0.4): Extracting archive
  - Installing sebastian/object-enumerator (4.0.4): Extracting archive
  - Installing sebastian/global-state (5.0.3): Extracting archive
  - Installing sebastian/exporter (4.0.4): Extracting archive
  - Installing sebastian/environment (5.1.3): Extracting archive
  - Installing sebastian/diff (4.0.4): Extracting archive
  - Installing sebastian/comparator (4.0.6): Extracting archive
  - Installing sebastian/code-unit (1.0.8): Extracting archive
  - Installing sebastian/cli-parser (1.0.1): Extracting archive
  - Installing phpunit/php-timer (5.0.3): Extracting archive
  - Installing phpunit/php-text-template (2.0.4): Extracting archive
  - Installing phpunit/php-invoker (3.1.1): Extracting archive
  - Installing phpunit/php-file-iterator (3.0.6): Extracting archive
  - Installing theseer/tokenizer (1.2.1): Extracting archive
  - Installing sebastian/lines-of-code (1.0.3): Extracting archive
  - Installing sebastian/complexity (2.0.2): Extracting archive
  - Installing sebastian/code-unit-reverse-lookup (2.0.3): Extracting archive
  - Installing phpunit/php-code-coverage (9.2.10): Extracting archive
  - Installing doctrine/instantiator (1.4.0): Extracting archive
  - Installing phpspec/prophecy (v1.15.0): Extracting archive
  - Installing phar-io/version (3.1.0): Extracting archive
  - Installing phar-io/manifest (2.0.3): Extracting archive
  - Installing myclabs/deep-copy (1.10.2): Extracting archive
  - Installing phpunit/phpunit (9.5.10): Extracting archive
63 package suggestions were added by new dependencies, use `composer suggest` to see details.
Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
Generating optimized autoload files
&gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
77 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
&gt; @php artisan vendor:publish --tag=laravel-assets --ansi --force
No publishable resources for tag &#91;laravel-assets].
Publishing complete.
&gt; @php artisan key:generate --ansi
Application key set successfully.
lee@MacBook-Pro ~ % ls
Applications			Parallels
Desktop				Pictures
Documents			Public
Downloads			Sites
Library				Sunlogin Files
Movies				Virtual Machines.localized
Music				laraveldemo
OneDrive			sensors
lee@MacBook-Pro ~ % mv laraveldemo ./Downloads 
lee@MacBook-Pro ~ % ll
zsh: command not found: ll
lee@MacBook-Pro ~ % ls
Applications			Parallels
Desktop				Pictures
Documents			Public
Downloads			Sites
Library				Sunlogin Files
Movies				Virtual Machines.localized
Music				sensors
OneDrive
lee@MacBook-Pro ~ % ls 
Applications			Parallels
Desktop				Pictures
Documents			Public
Downloads			Sites
Library				Sunlogin Files
Movies				Virtual Machines.localized
Music				sensors
OneDrive
lee@MacBook-Pro ~ % cd Sites 
lee@MacBook-Pro Sites % ls
laraveldemo	localhost
lee@MacBook-Pro Sites % cd laraveldemo 
lee@MacBook-Pro laraveldemo % composer require nwidart/laravel-modules
Using version ^8.2 for nwidart/laravel-modules
./composer.json has been updated
Running composer update nwidart/laravel-modules
Loading composer repositories with package information
https://repo.packagist.org/ could not be fully loaded (curl error 28 while downloading https://repo.packagist.org/packages.json: Operation timed out after 10000 milliseconds with 0 out of 0 bytes received), package information was loaded from the local cache and may be out of date
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking nwidart/laravel-modules (8.2.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing nwidart/laravel-modules (8.2.0): Extracting archive
Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
Generating optimized autoload files
&gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: nwidart/laravel-modules
Package manifest generated successfully.
78 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
&gt; @php artisan vendor:publish --tag=laravel-assets --ansi --force
No publishable resources for tag &#91;laravel-assets].
Publishing complete.
lee@MacBook-Pro laraveldemo % php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"

Copied File &#91;/vendor/nwidart/laravel-modules/config/config.php] To &#91;/config/modules.php]
Publishing complete.
lee@MacBook-Pro laraveldemo % php artisan module:make Admin
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/module.json
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Routes/web.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Routes/api.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Resources/views/index.blade.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Resources/views/layouts/master.blade.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Config/config.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/composer.json
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Resources/assets/js/app.js
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Resources/assets/sass/app.scss
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/webpack.mix.js
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/package.json
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Database/Seeders/AdminDatabaseSeeder.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Providers/AdminServiceProvider.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Providers/RouteServiceProvider.php
Created : /Users/lee/Sites/laraveldemo/Modules/Admin/Http/Controllers/AdminController.php
Module &#91;Admin] created successfully.
lee@MacBook-Pro laraveldemo % composer dump-autoload
Generating optimized autoload files
&gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: nwidart/laravel-modules
Package manifest generated successfully.
Generated optimized autoload files containing 5099 classes
lee@MacBook-Pro laraveldemo % composer require "darkaonline/l5-swagger"
Using version ^8.0 for darkaonline/l5-swagger
./composer.json has been updated
Running composer update darkaonline/l5-swagger
Loading composer repositories with package information
Updating dependencies
Lock file operations: 6 installs, 0 updates, 0 removals
  - Locking darkaonline/l5-swagger (8.0.9)
  - Locking doctrine/annotations (1.13.2)
  - Locking psr/cache (3.0.0)
  - Locking swagger-api/swagger-ui (v3.52.5)
  - Locking symfony/yaml (v5.4.0)
  - Locking zircote/swagger-php (3.3.3)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 6 installs, 0 updates, 0 removals
  - Installing symfony/yaml (v5.4.0): Extracting archive
  - Installing psr/cache (3.0.0): Extracting archive
  - Installing doctrine/annotations (1.13.2): Extracting archive
  - Installing zircote/swagger-php (3.3.3): Extracting archive
  - Installing swagger-api/swagger-ui (v3.52.5): Extracting archive
  - Installing darkaonline/l5-swagger (8.0.9): Extracting archive
Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
Generating optimized autoload files
&gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&gt; @php artisan package:discover --ansi
Discovered Package: darkaonline/l5-swagger
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: nwidart/laravel-modules
Package manifest generated successfully.
80 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
&gt; @php artisan vendor:publish --tag=laravel-assets --ansi --force
No publishable resources for tag &#91;laravel-assets].
Publishing complete.
lee@MacBook-Pro laraveldemo % php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"
Copied File &#91;/vendor/darkaonline/l5-swagger/config/l5-swagger.php] To &#91;/config/l5-swagger.php]
Copied Directory &#91;/vendor/darkaonline/l5-swagger/resources/views] To &#91;/resources/views/vendor/l5-swagger]
Publishing complete.
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default

   ErrorException 

  Required @OA\Info() not found

  at vendor/zircote/swagger-php/src/Logger.php:40
     36▕         $this-&gt;log = function ($entry, $type) {
     37▕             if ($entry instanceof Exception) {
     38▕                 $entry = $entry-&gt;getMessage();
     39▕             }
  ➜  40▕             trigger_error($entry, $type);
     41▕         };
     42▕     }
     43▕ 
     44▕     public static function getInstance(): Logger

      +27 vendor frames 
  28  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default

   ErrorException 

  Required @OA\Info() not found

  at vendor/zircote/swagger-php/src/Logger.php:40
     36▕         $this-&gt;log = function ($entry, $type) {
     37▕             if ($entry instanceof Exception) {
     38▕                 $entry = $entry-&gt;getMessage();
     39▕             }
  ➜  40▕             trigger_error($entry, $type);
     41▕         };
     42▕     }
     43▕ 
     44▕     public static function getInstance(): Logger

      +27 vendor frames 
  28  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default

   ErrorException 

  Required @OA\Info() not found

  at vendor/zircote/swagger-php/src/Logger.php:40
     36▕         $this-&gt;log = function ($entry, $type) {
     37▕             if ($entry instanceof Exception) {
     38▕                 $entry = $entry-&gt;getMessage();
     39▕             }
  ➜  40▕             trigger_error($entry, $type);
     41▕         };
     42▕     }
     43▕ 
     44▕     public static function getInstance(): Logger

      +27 vendor frames 
  28  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default

   ErrorException 

  Required @OA\PathItem() not found

  at vendor/zircote/swagger-php/src/Logger.php:40
     36▕         $this-&gt;log = function ($entry, $type) {
     37▕             if ($entry instanceof Exception) {
     38▕                 $entry = $entry-&gt;getMessage();
     39▕             }
  ➜  40▕             trigger_error($entry, $type);
     41▕         };
     42▕     }
     43▕ 
     44▕     public static function getInstance(): Logger

      +27 vendor frames 
  28  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"

Publishing complete.
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan
Laravel Framework 8.77.1

Usage:
  command &#91;options] &#91;arguments]

Options:
  -h, --help            Display help for the given command. When no command is given display help for the list command
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env&#91;=ENV]       The environment the command should run under
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  clear-compiled              Remove the compiled class file
  completion                  Dump the shell completion script
  db                          Start a new database CLI session
  down                        Put the application into maintenance / demo mode
  env                         Display the current framework environment
  help                        Display help for a command
  inspire                     Display an inspiring quote
  list                        List commands
  migrate                     Run the database migrations
  optimize                    Cache the framework bootstrap files
  serve                       Serve the application on the PHP development server
  test                        Run the application tests
  tinker                      Interact with your application
  up                          Bring the application out of maintenance mode
 auth
  auth:clear-resets           Flush expired password reset tokens
 cache
  cache:clear                 Flush the application cache
  cache:forget                Remove an item from the cache
  cache:table                 Create a migration for the cache database table
 config
  config:cache                Create a cache file for faster configuration loading
  config:clear                Remove the configuration cache file
 db
  db:seed                     Seed the database with records
  db:wipe                     Drop all tables, views, and types
 event
  event:cache                 Discover and cache the application's events and listeners
  event:clear                 Clear all cached events and listeners
  event:generate              Generate the missing events and listeners based on registration
  event:list                  List the application's events and listeners
 key
  key:generate                Set the application key
 l5-swagger
  l5-swagger:generate         Regenerate docs
 make
  make:cast                   Create a new custom Eloquent cast class
  make:channel                Create a new channel class
  make:command                Create a new Artisan command
  make:component              Create a new view component class
  make:controller             Create a new controller class
  make:event                  Create a new event class
  make:exception              Create a new custom exception class
  make:factory                Create a new model factory
  make:job                    Create a new job class
  make:listener               Create a new event listener class
  make:mail                   Create a new email class
  make:middleware             Create a new middleware class
  make:migration              Create a new migration file
  make:model                  Create a new Eloquent model class
  make:notification           Create a new notification class
  make:observer               Create a new observer class
  make:policy                 Create a new policy class
  make:provider               Create a new service provider class
  make:request                Create a new form request class
  make:resource               Create a new resource
  make:rule                   Create a new validation rule
  make:seeder                 Create a new seeder class
  make:test                   Create a new test class
 migrate
  migrate:fresh               Drop all tables and re-run all migrations
  migrate:install             Create the migration repository
  migrate:refresh             Reset and re-run all migrations
  migrate:reset               Rollback all database migrations
  migrate:rollback            Rollback the last database migration
  migrate:status              Show the status of each migration
 model
  model:prune                 Prune models that are no longer needed
 module
  module:delete               Delete a module from the application
  module:disable              Disable the specified module.
  module:dump                 Dump-autoload the specified module or for all module.
  module:enable               Enable the specified module.
  module:install              Install the specified module by given package name (vendor/name).
  module:list                 Show list of all modules.
  module:make                 Create a new module.
  module:make-command         Generate new Artisan command for the specified module.
  module:make-controller      Generate new restful controller for the specified module.
  module:make-event           Create a new event class for the specified module
  module:make-factory         Create a new model factory for the specified module.
  module:make-job             Create a new job class for the specified module
  module:make-listener        Create a new event listener class for the specified module
  module:make-mail            Create a new email class for the specified module
  module:make-middleware      Create a new middleware class for the specified module.
  module:make-migration       Create a new migration for the specified module.
  module:make-model           Create a new model for the specified module.
  module:make-notification    Create a new notification class for the specified module.
  module:make-policy          Create a new policy class for the specified module.
  module:make-provider        Create a new service provider class for the specified module.
  module:make-request         Create a new form request class for the specified module.
  module:make-resource        Create a new resource class for the specified module.
  module:make-rule            Create a new validation rule for the specified module.
  module:make-seed            Generate new seeder for the specified module.
  module:make-test            Create a new test class for the specified module.
  module:migrate              Migrate the migrations from the specified module or from all modules.
  module:migrate-refresh      Rollback &amp; re-migrate the modules migrations.
  module:migrate-reset        Reset the modules migrations.
  module:migrate-rollback     Rollback the modules migrations.
  module:migrate-status       Status for all module migrations
  module:publish              Publish a module's assets to the application
  module:publish-config       Publish a module's config files to the application
  module:publish-migration    Publish a module's migrations to the application
  module:publish-translation  Publish a module's translations to the application
  module:route-provider       Create a new route service provider for the specified module.
  module:seed                 Run database seeder from the specified module or from all modules.
  module:setup                Setting up modules folders for first use.
  module:unuse                Forget the used module with module:use
  module:update               Update dependencies for the specified module or for all modules.
  module:use                  Use the specified module.
  module:v6:migrate           Migrate laravel-modules v5 modules statuses to v6.
 notifications
  notifications:table         Create a migration for the notifications table
 optimize
  optimize:clear              Remove the cached bootstrap files
 package
  package:discover            Rebuild the cached package manifest
 queue
  queue:batches-table         Create a migration for the batches database table
  queue:clear                 Delete all of the jobs from the specified queue
  queue:failed                List all of the failed queue jobs
  queue:failed-table          Create a migration for the failed queue jobs database table
  queue:flush                 Flush all of the failed queue jobs
  queue:forget                Delete a failed queue job
  queue:listen                Listen to a given queue
  queue:monitor               Monitor the size of the specified queues
  queue:prune-batches         Prune stale entries from the batches database
  queue:prune-failed          Prune stale entries from the failed jobs table
  queue:restart               Restart queue worker daemons after their current job
  queue:retry                 Retry a failed queue job
  queue:retry-batch           Retry the failed jobs for a batch
  queue:table                 Create a migration for the queue jobs database table
  queue:work                  Start processing jobs on the queue as a daemon
 route
  route:cache                 Create a route cache file for faster route registration
  route:clear                 Remove the route cache file
  route:list                  List all registered routes
 sail
  sail:install                Install Laravel Sail's default Docker Compose file
  sail:publish                Publish the Laravel Sail Docker files
 schedule
  schedule:list               List the scheduled commands
  schedule:run                Run the scheduled commands
  schedule:test               Run a scheduled command
  schedule:work               Start the schedule worker
 schema
  schema:dump                 Dump the given database schema
 session
  session:table               Create a migration for the session database table
 storage
  storage:link                Create the symbolic links configured for the application
 stub
  stub:publish                Publish all stubs that are available for customization
 vendor
  vendor:publish              Publish any publishable assets from vendor packages
 view
  view:cache                  Compile all of the application's Blade templates
  view:clear                  Clear all compiled view files
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % php artisan l5-swagger:generate

Regenerating docs default
lee@MacBook-Pro laraveldemo % 
</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/laravel/8773.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>node.js面试题大全－侧重后端应用与对Node核心的理解</title>
		<link>/uncategorized/8689.html</link>
					<comments>/uncategorized/8689.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Mon, 26 Aug 2019 12:05:37 +0000</pubDate>
				<category><![CDATA[Node]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[未分类]]></category>
		<category><![CDATA[node]]></category>
		<category><![CDATA[node.js]]></category>
		<guid isPermaLink="false">/?p=8689</guid>

					<description><![CDATA[Node是搞后端的，不应该被被归为前端，更不应该用前端的观点去理解，去面试node开发人员。所以这份面试题大全 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><strong>Node是搞后端的，不应该被被归为前端，更不应该用前端的观点去理解，去面试node开发人员。所以这份面试题大全，更侧重后端应用与对Node核心的理解。</strong></p>
<h3 id="为什么用nodejs它有哪些缺点">1、为什么用Nodejs,它有哪些缺点？</h3>
<ul>
<li>事件驱动，通过闭包很容易实现客户端的生命活期。</li>
<li>不用担心多线程，锁，并行计算的问题</li>
<li>V8引擎速度非常快</li>
<li>对于游戏来说，写一遍游戏逻辑代码，前端后端通用</li>
</ul>
<h4 id="当然nodejs也有一些缺点">当然Nodejs也有一些缺点：</h4>
<ul>
<li>nodejs更新很快，可能会出现版本兼容</li>
<li>nodejs还不算成熟，还没有大制作</li>
<li>nodejs不像其他的服务器，对于不同的链接，不支持进程和线程操作</li>
</ul>
<h3 id="什么是错误优先的回调函数">2、什么是错误优先的回调函数？</h3>
<ul>
<li>错误优先(Error-first)的回调函数（Error-First Callback）用于同时返回错误和数据。第一个参数返回错误，并且验证它是否出错；其他参数返回数据。
<pre><code class="hljs javascript">  fs.readFile(filePath, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">err, data</span>)

  </span>{

      <span class="hljs-keyword">if</span> (err)

      {

          <span class="hljs-comment">// 处理错误</span>

          <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.log(err);

      }

      <span class="hljs-built_in">console</span>.log(data);

  });</code></pre>
</li>
</ul>
<h3 id="如何避免回调地狱">3、如何避免回调地狱？</h3>
<h4 id="以下方式避免回调地狱">以下方式避免回调地狱</h4>
<ul>
<li>模块化：将回调函数转换为独立的函数</li>
<li>使用流程控制库，例如[aync]</li>
<li>使用Promise</li>
<li>使用aync/await</li>
</ul>
<h3 id="什么是promise">4、什么是Promise?</h3>
<ul>
<li>Promise可以帮助我们更好地处理异步操作。下面的实例中，100ms后会打印result字符串。catch用于错误处理。多个Promise可以链接起来。
<pre><code class="hljs coffeescript">  <span class="hljs-keyword">new</span> Promise(<span class="hljs-function"><span class="hljs-params">(resolve, reject)</span> =&gt;</span>

      {

          setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span>

          {

              resolve(<span class="hljs-string">'result'</span>);

          }, <span class="hljs-number">100</span>)

      })

      .<span class="hljs-keyword">then</span>(<span class="hljs-built_in">console</span>.log)

      .<span class="hljs-keyword">catch</span>(<span class="hljs-built_in">console</span>.error);</code></pre>
</li>
</ul>
<h3 id="用什么工具保证一致的代码风格为什么要这样">5、用什么工具保证一致的代码风格？为什么要这样？</h3>
<ul>
<li>团队协作时，保证一致的代码风格是非常重要的，这样团队成员才可以更快地修改代码，而不需要每次去适应新的风格。这些工具可以帮助我们：</li>
<li>[ESLint] (<a class="uri" href="/goto/scp8" rel="nofollow">http://eslint.org/</a>)</li>
<li>[Standard] (<a class="uri" href="/goto/temy" rel="nofollow">https://standardjs.com/</a>)</li>
<li>JSLint</li>
<li>JSHint</li>
<li>ESLint</li>
<li>JSCS推荐</li>
</ul>
<h3 id="什么是stub举例说明">6、什么是stub？举例说明</h3>
<ul>
<li>stub用于模块的行为。测试时，stub可以为函数调用返回模拟的结果。比如说，我们写文件时，实际上并不需要真正去写。
<pre><code class="hljs javascript">      <span class="hljs-keyword">var</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);
      <span class="hljs-keyword">var</span> writeFileStub = sinon.stub(fs, <span class="hljs-string">'writeFile'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">path, data, cb</span>)

      </span>{

          <span class="hljs-keyword">return</span> cb(<span class="hljs-literal">null</span>);

      });

      expect(writeFileStub).to.be.called;

      writeFileStub.restore();</code></pre>
</li>
</ul>
<h3 id="什么是测试金字塔举例说明">7、什么是测试金字塔？举例说明</h3>
<ul>
<li>测试金字塔反应了需要写的单元测试，集成测试以及端到端测试的比例：<br />
<img decoding="async" src="https://images2018.cnblogs.com/blog/1201653/201711/1201653-20171127104813253-720616924.png" /></li>
<li>测试HTTP接口时应该是这样的：</li>
<li>很多单元测试，分别测试各个模块(依赖需要stub)</li>
<li>较少的集成测试，测试各个模块之间的交互(依赖不能stub)</li>
<li>少量端到端测试，去调用真正地接口(依赖不能stub)</li>
</ul>
<h3 id="如何用node监听80端口">8、如何用Node监听80端口</h3>
<ul>
<li>这题有陷阱！在类Unix系统中你不应该去监听80端口，因为这需要超级用户权限。因此不推荐让你的应用直接监听这个端口。</li>
<li>目前，如果你一定要让你的应用80端口的话，你可以有通过在Node应用的前方再添加一层反向代理（例如nginx）来实现，如下图。否则，建议你直接监听大于1024的端口<br />
<img decoding="async" src="https://images2018.cnblogs.com/blog/1201653/201711/1201653-20171127113957737-1743742030.png" /></li>
<li>方向代理指的是以代理服务器来接收Internet上的连接请求，然后将请求转发给内部网络上的服务器， 并且将服务器返回的结果发送给客户端。</li>
</ul>
<h3 id="什么是事件循环">9、什么是事件循环</h3>
<ul>
<li>Node采用的是单线程的处理机制(所有的I/O请求都采用非阻塞的工作方式)，至少从Node.js开发者的角度是这样的。而在底层，Node.js借助libuv来作为抽象封装层，从而屏蔽不同操作系统的差异，Node可以借助livuv来实现线程。下图表示Node和libuv的关系<br />
<img decoding="async" src="https://images2018.cnblogs.com/blog/1201653/201711/1201653-20171127114014956-1412280481.png" /></li>
<li>Libuv库负责Node API的执行。它将不同的任务分配给不同的线程，形成一个事件循环，以异步的方式将任务的执行结果返回给V8引擎。可以简单用下面这张图来表示<br />
<img decoding="async" src="https://images2018.cnblogs.com/blog/1201653/201711/1201653-20171127114035472-900672231.png" /></li>
<li>每一个I/O都需要一个回调函数————一旦执行完便堆到事件循环上用于执行</li>
</ul>
<h3 id="运算错误与程序员错误的区别">10、运算错误与程序员错误的区别</h3>
<ul>
<li>运算错误并不是bug，这是和系统相关的问题，例如请求超时或者硬件故障。而程序员错误就是所谓的bug</li>
</ul>
<h3 id="使用npm有哪些好处">11、使用NPM有哪些好处？</h3>
<ul>
<li>通过NPM，你可以安装和管理项目的依赖，并且能够指明依赖项的具体版本号。对于Node应用开发而言，你可以通过<code>package.json</code>文件来管理项目信息，配置脚本，以及指明依赖的具体版本</li>
</ul>
<h3 id="什么是stub举个使用场景">12、什么是stub？举个使用场景</h3>
<ul>
<li>stub是用于模拟一个组件或模块的函数或程序。在测试用例中，简单的说，你可以用stub去模拟一个方法，从而避免调用真实的方法，使用stub你还可以返回虚构的结果。你可以配合断言使用stub。</li>
<li>举个例子，在一个读取文件的场景中，当你不想读取一个真正的文件时：
<pre><code class="hljs javascript">  <span class="hljs-keyword">var</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>); <span class="hljs-keyword">var</span> readFileStub = sinon.stub(fs, <span class="hljs-string">'readFile'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">path, cb</span>) </span>{ <span class="hljs-keyword">return</span> cb(<span class="hljs-literal">null</span>, <span class="hljs-string">'filecontent'</span>); }); expect(readFileStub).to.be.called; readFileStub.restore(); </code></pre>
</li>
</ul>
<p><code>在单元测试中：Stub是完全模拟一个外部依赖，而Mock常用来判断测试通过还是失败</code></p>
<h1>node开发技能图解</h1>
<p><img decoding="async" src="https://images2015.cnblogs.com/blog/730090/201509/730090-20150919214515695-745120854.jpg" alt="" /></p>
<h1><a id="user-content-起源" class="anchor" href="/goto/i8j3" rel="nofollow"></a>起源</h1>
<ul>
<li>node正风生火起，很多介绍却停留在入门阶段，无法投入生产</li>
<li>node相关的高质量面试题更是少之又少，很难全面考查应聘者的node能力</li>
<li>许多文章在讲第三方类库，可是这些库质量差距较大，一旦遇到问题怎么办</li>
<li>必需的，全面了解node核心才能成为一名合格的node开发人员</li>
</ul>
<h1><a id="user-content-目标与原则" class="anchor" href="/goto/ww2r" rel="nofollow"></a>目标与原则</h1>
<ul>
<li>前后端兼顾，更侧重后端</li>
<li>理论实战兼顾，侧重考察对实战中应用较多的理论的理解</li>
<li>参考答案简单明了，一针见血，不为追求严谨而浪费口舌，绕弯子</li>
<li>尽量用代码讲清理论的应用与区别，以接地气</li>
<li>终极目标是让大家对node有一个快速完整的认识</li>
</ul>
<h1><a id="user-content-内容大纲" class="anchor" href="/goto/hogw" rel="nofollow"></a>内容大纲</h1>
<ul>
<li>javascript高级话题(面向对象，作用域，闭包，设计模式等)</li>
<li>node核心内置类库(事件，流，文件，网络等)</li>
<li>node高级话题(异步，部署，性能调优，异常调试等)</li>
<li>常用知名第三方类库(Async, Express等)</li>
<li>其它相关后端常用技术(MongoDB, Redis, Apache, Nginx等)</li>
<li>常用前端技术(Html5, CSS3, JQuery等)</li>
</ul>
<h2><a id="user-content-javascript高级话题面向对象作用域闭包设计模式等" class="anchor" href="/goto/gaiy" rel="nofollow"></a><a name="user-content-jsAdvanced"></a>javascript高级话题(面向对象，作用域，闭包，设计模式等)</h2>
<ul>
<li><strong>1. 常用js类定义的方法有哪些？</strong></li>
</ul>
<p>参考答案：主要有构造函数原型和对象创建两种方法。原型法是通用老方法，对象创建是ES5推荐使用的方法.目前来看，原型法更普遍.</p>
<p>代码演示<br />
1) 构造函数方法定义类</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">Person(){
        <span class="pl-v">this.<span class="pl-c1">name = <span class="pl-s"><span class="pl-pds">'michaelqin';
    }
    Person.prototype.sayName = function(){
        alert(this.name);
    }

    var person = new Person();
    person.sayName();</span></span></span></span></span></span></pre>
</div>
<p>2) 对象创建方法定义类</p>
<pre><code class="hljs javascript">    <span class="hljs-keyword">var</span> Person = {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'michaelqin'</span>,
        <span class="hljs-attr">sayName</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>()</span>{ alert(<span class="hljs-keyword">this</span>.name); }
    };

    <span class="hljs-keyword">var</span> person = <span class="hljs-built_in">Object</span>.create(Person);
    person.sayName();
</code></pre>
<ul>
<li><strong>2. js类继承的方法有哪些</strong></li>
</ul>
<p>参考答案：原型链法，属性复制法和构造器应用法. 另外，由于每个对象可以是一个类，这些方法也可以用于对象类的继承．</p>
<p>代码演示<br />
1) 原型链法</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">Animal() {
        <span class="pl-v">this.<span class="pl-c1">name = <span class="pl-s"><span class="pl-pds">'animal';
    }
    Animal.prototype.sayName = {
        alert(this.name);
    };

    function Person() {}
    Person.prototype = Animal.prototype; <span class="pl-c">// 人继承自动物
    Person.prototype.constructor = 'Person'; // 更新构造函数为人</span></span></span></span></span></span></span></pre>
</div>
<p>2) 属性自制法</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">Animal() {
        <span class="pl-v">this.<span class="pl-c1">name = <span class="pl-s"><span class="pl-pds">'animal';
    }
    Animal.prototype.sayName = {
        alert(this.name);
    };

    function Person() {}

    for(prop in Animal.prototype) {
        Person.prototype[prop] = Animal.prototype[prop];
    } <span class="pl-c">// 复制动物的所有属性到人量边
    Person.prototype.constructor = 'Person'; // 更新构造函数为人</span></span></span></span></span></span></span></pre>
</div>
<p>3) 构造器应用法</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">Animal() {
        <span class="pl-v">this.<span class="pl-c1">name = <span class="pl-s"><span class="pl-pds">'animal';
    }
    Animal.prototype.sayName = {
        alert(this.name);
    };

    function Person() {
        Animal.call(this); <span class="pl-c">// apply, call, bind方法都可以．细微区别，后面会提到．
    }</span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>3. js类多重继承的实现方法是怎么样的?</strong></li>
</ul>
<p>参考答案：就是类继承里边的属性复制法来实现．因为当所有父类的prototype属性被复制后，子类自然拥有类似行为和属性．</p>
<ul>
<li><strong>4. js里的作用域是什么样子的？</strong></li>
</ul>
<p>参考答案：大多数语言里边都是块作作用域，以{}进行限定，js里边不是．js里边叫函数作用域，就是一个变量在全函数里有效．比如有个变量p1在函数最后一行定义，第一行也有效，但是值是undefined.</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">var globalVar = <span class="pl-s"><span class="pl-pds">'global var';

    function <span class="pl-en">test() {
        <span class="pl-c1">alert(globalVar); <span class="pl-c">// undefined, 因为globalVar在本函数内被重定义了，导致全局失效，这里使用函数内的变量值，可是此时还没定义
        var globalVar = 'overrided var'; //　globalVar在本函数内被重定义
        alert(globalVar);　// overrided var
    }
    alert(globalVar); // global var，使用全局变量</span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>5. js里边的this指的是什么?</strong></li>
</ul>
<p>参考答案: this指的是对象本身，而不是构造函数．</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">Person() {
    }
    Person.<span class="pl-c1">prototype.sayName() { alert(<span class="pl-v">this.name); }

    var person1 = new Person();
    person1.name = <span class="pl-s"><span class="pl-pds">'michaelqin';
    person1.sayName(); <span class="pl-c">// michaelqin</span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>6. apply, call和bind有什么区别?</strong></li>
</ul>
<p>参考答案：三者都可以把一个函数应用到其他对象上，注意不是自身对象．apply,call是直接执行函数调用，bind是绑定，执行需要再次调用．apply和call的区别是apply接受数组作为参数，而call是接受逗号分隔的无限多个参数列表，</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">Person() {
    }
    Person.<span class="pl-c1">prototype.sayName() { alert(<span class="pl-v">this.name); }

    var obj = {name: <span class="pl-s"><span class="pl-pds">'michaelqin'}; <span class="pl-c">// 注意这是一个普通对象，它不是Person的实例
    1) apply
    Person.prototype.sayName.apply(obj, [param1, param2, param3]);

    2) call
    Person.prototype.sayName.call(obj, param1, param2, param3);

    3) bind
    var sn = Person.prototype.sayName.bind(obj);    
    sn([param1, param2, param3]); // bind需要先绑定，再执行 
    sn(param1, param2, param3); // bind需要先绑定，再执行</span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>7. caller, callee和arguments分别是什么?</strong></li>
</ul>
<p>参考答案: caller,callee之间的关系就像是employer和employee之间的关系，就是调用与被调用的关系，二者返回的都是函数对象引用．arguments是函数的所有参数列表，它是一个类数组的变量．</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">function <span class="pl-en">parent(<span class="pl-smi">param1, param2, param3) {
        child(param1, param2, param3);
    }

    function child() {
        console<span class="pl-c1">.log(arguments); <span class="pl-c">// { '0': 'mqin1', '1': 'mqin2', '2': 'mqin3' }
        console.log(arguments.callee); // [Function: child]
        console.log(child.caller); // [Function: parent]
    }

    parent(<span class="pl-s"><span class="pl-pds">'mqin1', 'mqin2', 'mqin3');</span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>8. 什么是闭包，闭包有哪些用处?</strong></li>
</ul>
<p>参考答案: 闭包这个术语它其实什么都不是．非要讲它是什么的话，两个字函数，更多字嵌套函数的父子自我引用关系．所有函数都是闭包．通俗的说，闭包就是作用域范围，因为js是函数作用域，所以函数就是闭包．全局函数的作用域范围就是全局，所以无须讨论．更多的应用其实是在内嵌函数，这就会涉及到内嵌作用域，或者叫作用域链．说到内嵌，其实就是父子引用关系(父函数包含子函数，子函数因为函数作用域又引用父函数，这不是死结吗？所以叫闭包），这就会带来另外一个问题，什么时候引用结束？如果不结束，就会一直占用内存，引起内存泄漏．好吧，不用的时候就引用设为空，死结就解开了．</p>
<ul>
<li><strong>9. defineProperty, hasOwnProperty, isEnumerable都是做什么用的？</strong></li>
</ul>
<p>参考答案：Object.defineProperty(obj, prop, descriptor)用来给对象定义属性,有value,writable,configurable,enumerable,set/get等.hasOwnProerty用于检查某一属性是不是存在于对象本身，继承来的父亲的属性不算．isEnumerable用来检测某一属性是否可遍历，也就是能不能用for..in循环来取到.</p>
<ul>
<li><strong>10. js常用设计模式的实现思路，单例，工厂，代理，装饰，观察者模式等</strong></li>
</ul>
<p>参考答案：</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-c1">1) 单例：　任意对象都是单例，无须特别处理
    <span class="pl-k">var obj = {name: <span class="pl-s"><span class="pl-pds">'michaelqin', age: 30};

    2) 工厂: 就是同样形式参数返回不同的实例
    function <span class="pl-en">Person() { <span class="pl-v">this.name = 'Person1'; }
    function Animal() { this.name = 'Animal1'; }

    function Factory() {}
    Factory.prototype.getInstance = function(<span class="pl-smi">className) {
        return eval('new ' + className + '()');
    }

    var factory = new Factory();
    var obj1 = factory.getInstance('Person');
    var obj2 = factory.getInstance('Animal');
    console.log(obj1.name); <span class="pl-c">// Person1
    console.log(obj2.name); // Animal1

    3) 代理: 就是新建个类调用老类的接口,包一下
    function Person() { }
    Person.prototype.sayName = function() { console.log('michaelqin'); }
    Person.prototype.sayAge = function() { console.log(30); }

    function PersonProxy() { 
        this.person = new Person();
        var that = this;
        this.callMethod = function(functionName) {
            console.log('before proxy:', functionName);
            that.person[functionName](); // 代理
            console.log('after proxy:', functionName);
        }
    }

    var pp = new PersonProxy();
    pp.callMethod('sayName'); // 代理调用Person的方法sayName()
    pp.callMethod('sayAge'); // 代理调用Person的方法sayAge() 

    4) 观察者: 就是事件模式，比如按钮的onclick这样的应用.
    function Publisher() {
        this.listeners = [];
    }
    Publisher.prototype = {
        'addListener': function(listener) {
            this.listeners.push(listener);
        },

        'removeListener': function(listener) {
            delete this.listeners[listener];
        },

        'notify': function(obj) {
            for(var i = 0; i &lt; this.listeners.length; i++) {
                var listener = this.listeners[i];
                if (typeof listener !== 'undefined') {
                    listener.process(obj);
                }
            }
        }
    }; // 发布者

    function Subscriber() {

    }
    Subscriber.prototype = {
        'process': function(obj) {
            console.log(obj);
        }
    };　// 订阅者


    var publisher = new Publisher();
    publisher.addListener(new Subscriber());
    publisher.addListener(new Subscriber());
    publisher.notify({name: 'michaelqin', ageo: 30}); // 发布一个对象到所有订阅者
    publisher.notify('2 subscribers will both perform process'); // 发布一个字符串到所有订阅者</span></span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>11. 列举数组相关的常用方法</strong></li>
</ul>
<p>参考答案: push/pop, shift/unshift, split/join, slice/splice/concat, sort/reverse, map/reduce, forEach, filter</p>
<ul>
<li><strong>12. 列举字符串相关的常用方法</strong></li>
</ul>
<p>参考答案: indexOf/lastIndexOf/charAt, split/match/test, slice/substring/substr, toLowerCase/toUpperCase</p>
<h2><a id="user-content-node核心内置类库事件流文件网络等" class="anchor" href="/goto/143g" rel="nofollow"></a><a name="user-content-nodeCore"></a>node核心内置类库(事件，流，文件，网络等)</h2>
<h3><a id="user-content-node概览" class="anchor" href="/goto/guxb" rel="nofollow"></a>node概览</h3>
<ul>
<li><strong>1. 为什么要用node?</strong></li>
</ul>
<p>参考答案: 总结起来node有以下几个特点:简单强大，轻量可扩展．简单体现在node使用的是javascript,json来进行编码，人人都会；强大体现在非阻塞IO,可以适应分块传输数据，较慢的网络环境，尤其擅长高并发访问；轻量体现在node本身既是代码，又是服务器，前后端使用统一语言;可扩展体现在可以轻松应对多实例，多服务器架构，同时有海量的第三方应用组件．</p>
<ul>
<li><strong>2. node的构架是什么样子的?</strong></li>
</ul>
<p>参考答案: 主要分为三层，应用app &gt;&gt; V8及node内置架构 &gt;&gt; 操作系统. V8是node运行的环境，可以理解为node虚拟机．node内置架构又可分为三层: 核心模块(javascript实现) &gt;&gt; c++绑定 &gt;&gt; libuv + CAes + http.</p>
<p><a href="/goto/x4ix" target="_blank" rel="nofollow noopener"><img decoding="async" src="https://camo.githubusercontent.com/233315761d49d4c75fe7969e36bda22ecf5bbc0f/687474703a2f2f6a6f616f7073696c76612e6769746875622e696f2f74616c6b732f456e642d746f2d456e642d4a6176615363726970742d776974682d7468652d4d45414e2d537461636b2f696d672f6e6f64656a732d617263682d7070742e706e67" alt="" data-canonical-src="http://joaopsilva.github.io/talks/End-to-End-JavaScript-with-the-MEAN-Stack/img/nodejs-arch-ppt.png" /></a></p>
<ul>
<li><strong>3. node有哪些核心模块?</strong></li>
</ul>
<p>参考答案: EventEmitter, Stream, FS, Net和全局对象</p>
<h3><a id="user-content-node全局对象" class="anchor" href="/goto/x7hg" rel="nofollow"></a>node全局对象</h3>
<ul>
<li><strong>1. node有哪些全局对象?</strong></li>
</ul>
<p>参考答案: process, console, Buffer和exports</p>
<ul>
<li><strong>2. process有哪些常用方法?</strong></li>
</ul>
<p>参考答案: process.stdin, process.stdout, process.stderr, process.on, process.env, process.argv, process.arch, process.platform, process.exit</p>
<ul>
<li><strong>3. console有哪些常用方法?</strong></li>
</ul>
<p>参考答案: console.log/console.info, console.error/console.warning, console.time/console.timeEnd, console.trace, console.table</p>
<ul>
<li><strong>4. node有哪些定时功能?</strong></li>
</ul>
<p>参考答案: setTimeout/clearTimeout, setInterval/clearInterval, setImmediate/clearImmediate, process.nextTick</p>
<ul>
<li><strong>5. node中的事件循环是什么样子的?</strong></li>
</ul>
<p>参考答案: event loop其实就是一个事件队列，先加入先执行，执行完一次队列，再次循环遍历看有没有新事件加入队列．执行中的叫IO events, setImmediate是在当前队列立即执行,setTimout/setInterval是把执行定时到下一个队列，process.nextTick是在当前执行完，下次遍历前执行．所以总体顺序是: IO events &gt;&gt; setImmediate &gt;&gt; setTimeout/setInterval &gt;&gt; process.nextTick</p>
<ul>
<li><strong>6. node中的Buffer如何应用?</strong></li>
</ul>
<p>参考答案: Buffer是用来处理二进制数据的，比如图片，mp3,数据库文件等.Buffer支持各种编码解码，二进制字符串互转．</p>
<h3><a id="user-content-eventemitter" class="anchor" href="/goto/9iwd" rel="nofollow"></a>EventEmitter</h3>
<ul>
<li><strong>1. 什么是EventEmitter?</strong></li>
</ul>
<p>参考答案: EventEmitter是node中一个实现观察者模式的类，主要功能是监听和发射消息，用于处理多模块交互问题.</p>
<ul>
<li><strong>2. 如何实现一个EventEmitter?</strong></li>
</ul>
<p>参考答案: 主要分三步：定义一个子类，调用构造函数，继承EventEmitter</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">var util = <span class="pl-c1">require(<span class="pl-s"><span class="pl-pds">'util');
    var EventEmitter = require('events').EventEmitter;

    function <span class="pl-en">MyEmitter() {
        EventEmitter.call(<span class="pl-v">this);
    } <span class="pl-c">// 构造函数

    util.inherits(MyEmitter, EventEmitter); // 继承

    var em = new MyEmitter();
    em.on('hello', function(<span class="pl-smi">data) {
        console.log('收到事件hello的数据:', data);
    }); // 接收事件，并打印到控制台
    em.emit('hello', 'EventEmitter传递消息真方便!');</span></span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>3. EventEmitter有哪些典型应用?</strong></li>
</ul>
<p>参考答案: 1) 模块间传递消息 2) 回调函数内外传递消息 3) 处理流数据，因为流是在EventEmitter基础上实现的. 4) 观察者模式发射触发机制相关应用</p>
<ul>
<li><strong>4. 怎么捕获EventEmitter的错误事件?</strong></li>
</ul>
<p>参考答案: 监听error事件即可．如果有多个EventEmitter,也可以用domain来统一处理错误事件.</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">var domain = <span class="pl-c1">require(<span class="pl-s"><span class="pl-pds">'domain');
    var myDomain = domain.create();
    myDomain.on('error', function(<span class="pl-smi">err){
        <span class="pl-en">console.log('domain接收到的错误事件:', err);
    }); <span class="pl-c">// 接收事件并打印
    myDomain.run(function(){
        var emitter1 = new MyEmitter();
        emitter1.emit('error', '错误事件来自emitter1');
        emitter2 = new MyEmitter();
        emitter2.emit('error', '错误事件来自emitter2');
    });</span></span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>5. EventEmitter中的newListenser事件有什么用处?</strong></li>
</ul>
<p>参考答案: newListener可以用来做事件机制的反射，特殊应用，事件管理等．当任何on事件添加到EventEmitter时，就会触发newListener事件，基于这种模式，我们可以做很多自定义处理.</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre><span class="pl-k">var emitter3 = new <span class="pl-en">MyEmitter();
emitter3.on(<span class="pl-s"><span class="pl-pds">'newListener', function(<span class="pl-smi">name, listener) {
    console<span class="pl-c1">.log("新事件的名字:", name);
    console.log("新事件的代码:", listener);
    setTimeout(function(){ console.log("我是自定义延时处理机制"); }, 1000);
});
emitter3.on('hello', function(){
    console.log('hello　node');
});</span></span></span></span></span></span></pre>
</div>
<h3><a id="user-content-stream" class="anchor" href="/goto/irdg" rel="nofollow"></a>Stream</h3>
<ul>
<li><strong>1. 什么是Stream?</strong></li>
</ul>
<p>参考答案: stream是基于事件EventEmitter的数据管理模式．由各种不同的抽象接口组成，主要包括可写，可读，可读写，可转换等几种类型．</p>
<ul>
<li><strong>2. Stream有什么好处?</strong></li>
</ul>
<p>参考答案: 非阻塞式数据处理提升效率，片断处理节省内存，管道处理方便可扩展等.</p>
<ul>
<li><strong>3. Stream有哪些典型应用?</strong></li>
</ul>
<p>参考答案: 文件，网络，数据转换，音频视频等.</p>
<ul>
<li><strong>4. 怎么捕获Stream的错误事件?</strong></li>
</ul>
<p>参考答案: 监听error事件，方法同EventEmitter.</p>
<ul>
<li><strong>5. 有哪些常用Stream,分别什么时候使用?</strong></li>
</ul>
<p>参考答案: Readable为可被读流，在作为输入数据源时使用；Writable为可被写流,在作为输出源时使用；Duplex为可读写流,它作为输出源接受被写入，同时又作为输入源被后面的流读出．Transform机制和Duplex一样，都是双向流，区别时Transfrom只需要实现一个函数_transfrom(chunk, encoding, callback);而Duplex需要分别实现_read(size)函数和_write(chunk, encoding, callback)函数.</p>
<ul>
<li><strong>6. 实现一个Writable Stream?</strong></li>
</ul>
<p>参考答案: 三步走:1)构造函数call Writable 2)　继承Writable 3) 实现_write(chunk, encoding, callback)函数</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre><span class="pl-k">var Writable = <span class="pl-c1">require(<span class="pl-s"><span class="pl-pds">'stream').Writable;
var util = require('util');

function <span class="pl-en">MyWritable(<span class="pl-smi">options) {
    Writable.call(<span class="pl-v">this, options);
} <span class="pl-c">// 构造函数
util.inherits(MyWritable, Writable); // 继承自Writable
MyWritable.prototype._write = function(chunk, encoding, callback) {
    console.log("被写入的数据是:", chunk.toString()); // 此处可对写入的数据进行处理
    callback();
};

process.stdin.pipe(new MyWritable()); // stdin作为输入源，MyWritable作为输出源   </span></span></span></span></span></span></span></span></pre>
</div>
<h3><a id="user-content-文件系统" class="anchor" href="/goto/pu7z" rel="nofollow"></a>文件系统</h3>
<ul>
<li><strong>1. 内置的fs模块架构是什么样子的?</strong></li>
</ul>
<p>参考答案: fs模块主要由下面几部分组成: 1) POSIX文件Wrapper,对应于操作系统的原生文件操作 2) 文件流 fs.createReadStream和fs.createWriteStream 3) 同步文件读写,fs.readFileSync和fs.writeFileSync 4) 异步文件读写, fs.readFile和fs.writeFile</p>
<ul>
<li><strong>2. 读写一个文件有多少种方法?</strong></li>
</ul>
<p>参考答案: 总体来说有四种: 1) POSIX式低层读写 2) 流式读写 3) 同步文件读写 4) 异步文件读写</p>
<ul>
<li><strong>3. 怎么读取json配置文件?</strong></li>
</ul>
<p>参考答案: 主要有两种方式，第一种是利用node内置的require(&#8216;data.json&#8217;)机制，直接得到js对象; 第二种是读入文件入内容，然后用JSON.parse(content)转换成js对象．二者的区别是require机制情况下，如果多个模块都加载了同一个json文件，那么其中一个改变了js对象，其它跟着改变，这是由node模块的缓存机制造成的，只有一个js模块对象; 第二种方式则可以随意改变加载后的js变量，而且各模块互不影响，因为他们都是独立的，是多个js对象.</p>
<ul>
<li><strong>4. fs.watch和fs.watchFile有什么区别，怎么应用?</strong></li>
</ul>
<p>参考答案: 二者主要用来监听文件变动．fs.watch利用操作系统原生机制来监听，可能不适用网络文件系统; fs.watchFile则是定期检查文件状态变更，适用于网络文件系统，但是相比fs.watch有些慢，因为不是实时机制．</p>
<h3><a id="user-content-网络" class="anchor" href="/goto/ybcr" rel="nofollow"></a>网络</h3>
<ul>
<li><strong>1. node的网络模块架构是什么样子的?</strong></li>
</ul>
<p>参考答案: node全面支持各种网络服务器和客户端，包括tcp, http/https, tcp, udp, dns, tls/ssl等.</p>
<ul>
<li><strong>2. node是怎样支持https,tls的?</strong></li>
</ul>
<p>参考答案: 主要实现以下几个步骤即可: 1) openssl生成公钥私钥 2) 服务器或客户端使用https替代http 3) 服务器或客户端加载公钥私钥证书</p>
<ul>
<li><strong>3. 实现一个简单的http服务器?</strong></li>
</ul>
<p>参考答案: 经典又很没毛意义的一个题目．思路是加载http模块，创建服务器，监听端口.</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">var http = <span class="pl-c1">require(<span class="pl-s"><span class="pl-pds">'http'); <span class="pl-c">// 加载http模块

    http.createServer(function(<span class="pl-smi">req, res) {
        res.writeHead(200, {'Content-Type': 'text/html'}); // 200代表状态成功, 文档类型是给浏览器识别用的
        res.write('&lt;meta charset="UTF-8"&gt; &lt;h1&gt;我是标题啊！&lt;/h1&gt; &lt;font color="red"&gt;这么原生，初级的服务器，下辈子能用着吗?!&lt;/font&gt;'); // 返回给客户端的html数据
        res.end(); // 结束输出流
    }).listen(3000); // 绑定3ooo, 查看效果请访问 http://localhost:3000/ </span></span></span></span></span></span></pre>
</div>
<h3><a id="user-content-child-process" class="anchor" href="/goto/obuo" rel="nofollow"></a>child-process</h3>
<ul>
<li><strong>1. 为什么需要child-process?</strong></li>
</ul>
<p>参考答案: node是异步非阻塞的，这对高并发非常有效．可是我们还有其它一些常用需求，比如和操作系统shell命令交互，调用可执行文件，创建子进程进行阻塞式访问或高CPU计算等，child-process就是为满足这些需求而生的．child-process顾名思义，就是把node阻塞的工作交给子进程去做．</p>
<ul>
<li><strong>2. exec,execFile,spawn和fork都是做什么用的?</strong></li>
</ul>
<p>参考答案: exec可以用操作系统原生的方式执行各种命令，如管道 cat ab.txt | grep hello; execFile是执行一个文件; spawn是流式和操作系统进行交互; fork是两个node程序(javascript)之间时行交互.</p>
<ul>
<li><strong>3. 实现一个简单的命令行交互程序?</strong></li>
</ul>
<p>参考答案: 那就用spawn吧.</p>
<p>代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">var cp = <span class="pl-c1">require(<span class="pl-s"><span class="pl-pds">'child_process');

    var child = cp.spawn('echo', ['你好', "钩子"]); <span class="pl-c">// 执行命令
    child.stdout.pipe(process.stdout); // child.stdout是输入流，process.stdout是输出流
    // 这句的意思是将子进程的输出作为当前程序的输入流，然后重定向到当前程序的标准输出，即控制台</span></span></span></span></span></pre>
</div>
<ul>
<li>4. 两个node程序之间怎样交互?</li>
</ul>
<p>参考答案: 用fork嘛，上面讲过了．原理是子程序用process.on, process.send，父程序里用child.on,child.send进行交互.<br />
代码演示</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-c1">1) fork<span class="pl-k">-parent.js
    var cp = require(<span class="pl-s"><span class="pl-pds">'child_process');
    var child = cp.fork('./fork-child.js');
    child.on('message', function(<span class="pl-smi">msg){
        <span class="pl-en">console.log('老爸从儿子接受到数据:', msg);
    });
    child.send('我是你爸爸，送关怀来了!');

    2) fork-child.js
    process.on('message', function(msg){
        console.log("儿子从老爸接收到的数据:", msg);
        process.send("我不要关怀，我要银民币！");
    });</span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>5. 怎样让一个js文件变得像linux命令一样可执行?</strong></li>
</ul>
<p>参考答案: 1) 在myCommand.js文件头部加入 #!/usr/bin/env node 2) chmod命令把js文件改为可执行即可 3) 进入文件目录，命令行输入myComand就是相当于node myComand.js了</p>
<ul>
<li><strong>6. child-process和process的stdin,stdout,stderror是一样的吗?</strong></li>
</ul>
<p>参考答案: 概念都是一样的，输入，输出，错误，都是流．区别是在父程序眼里，子程序的stdout是输入流，stdin是输出流．</p>
<h2><a id="user-content-node高级话题异步部署性能调优异常调试等" class="anchor" href="/goto/4f8b" rel="nofollow"></a><a name="user-content-nodeAdvanced"></a>node高级话题(异步，部署，性能调优，异常调试等)</h2>
<ul>
<li><strong>1. node中的异步和同步怎么理解</strong></li>
</ul>
<p>参考答案: node是单线程的，异步是通过一次次的循环事件队列来实现的．同步则是说阻塞式的IO,这在高并发环境会是一个很大的性能问题，所以同步一般只在基础框架的启动时使用，用来加载配置文件，初始化程序什么的．</p>
<ul>
<li><strong>2. 有哪些方法可以进行异步流程的控制?</strong></li>
</ul>
<p>参考答案: 1) 多层嵌套回调 2)　为每一个回调写单独的函数，函数里边再回调 3) 用第三方框架比方async, q, promise等</p>
<ul>
<li><strong>3. 怎样绑定node程序到80端口?</strong></li>
</ul>
<p>参考答案: 多种方式 1) sudo 2) apache/nginx代理 3) 用操作系统的firewall iptables进行端口重定向</p>
<ul>
<li><strong>4. 有哪些方法可以让node程序遇到错误后自动重启?</strong></li>
</ul>
<p>参考答案: 1) runit 2) forever 3) nohup npm start &amp;</p>
<ul>
<li><strong>5. 怎样充分利用多个CPU?</strong></li>
</ul>
<p>参考答案: 一个CPU运行一个node实例</p>
<ul>
<li><strong>6. 怎样调节node执行单元的内存大小?</strong></li>
</ul>
<p>参考答案: 用&#8211;max-old-space-size 和 &#8211;max-new-space-size 来设置 v8 使用内存的上限</p>
<ul>
<li><strong>7. 程序总是崩溃，怎样找出问题在哪里?</strong></li>
</ul>
<p>参考答案: 1) node &#8211;prof 查看哪些函数调用次数多 2) memwatch和heapdump获得内存快照进行对比，查找内存溢出</p>
<ul>
<li><strong>8. 有哪些常用方法可以防止程序崩溃?</strong></li>
</ul>
<p>参考答案: 1) try-catch-finally 2) EventEmitter/Stream error事件处理 3) domain统一控制 4) jshint静态检查 5) jasmine/mocha进行单元测试</p>
<ul>
<li><strong>9. 怎样调试node程序?</strong></li>
</ul>
<p>参考答案: node &#8211;debug app.js 和node-inspector</p>
<h2><a id="user-content-常用知名第三方类库async-express等" class="anchor" href="/goto/f3xe" rel="nofollow"></a><a name="user-content-node3rd"></a>常用知名第三方类库(Async, Express等)</h2>
<ul>
<li><strong>1. async都有哪些常用方法，分别是怎么用?</strong></li>
</ul>
<p>参考答案: async是一个js类库，它的目的是解决js中异常流程难以控制的问题．async不仅适用在node.js里，浏览器中也可以使用． 1) async.parallel并行执行完多个函数后，调用结束函数</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">async.parallel([
        function(){ ... },
        function(){ ... }
    ], callback);</span></pre>
</div>
<p>2) async.series串行执行完多个函数后，调用结束函数</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">async.series([
        function(){ ... },
        function(){ ... }
    ]);</span></pre>
</div>
<p>3) async.waterfall依次执行多个函数，后一个函数以前面函数的结果作为输入参数</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">async.waterfall([
        function(<span class="pl-smi">callback) {
            callback(<span class="pl-c1">null, <span class="pl-s"><span class="pl-pds">'one', 'two');
        },
        function(arg1, arg2, callback) {
          <span class="pl-c">// arg1 now equals 'one' and arg2 now equals 'two' 
            callback(null, 'three');
        },
        function(arg1, callback) {
            // arg1 now equals 'three' 
            callback(null, 'done');
        }
    ], function (err, result) {
        // result now equals 'done' 
    });</span></span></span></span></span></span></pre>
</div>
<p>4) async.map异步执行多个数组，返回结果数组</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">async.map([<span class="pl-s"><span class="pl-pds">'file1','file2','file3'], fs.stat, function(<span class="pl-smi">err, results){
        <span class="pl-c">// results is now an array of stats for each file 
    });</span></span></span></span></span></pre>
</div>
<p>5) async.filter异步过滤多个数组，返回结果数组</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">async.filter([<span class="pl-s"><span class="pl-pds">'file1','file2','file3'], fs.exists, function(<span class="pl-smi">results){
        <span class="pl-c">// results now equals an array of the existing files 
    });</span></span></span></span></span></pre>
</div>
<ul>
<li><strong>2. express项目的目录大致是什么样子的</strong></li>
</ul>
<p>参考答案: app.js, package.json, bin/www, public, routes, views.</p>
<ul>
<li><strong>3. express常用函数</strong></li>
</ul>
<p>参考答案: express.Router路由组件,app.get路由定向，app.configure配置，app.set设定参数,app.use使用中间件</p>
<ul>
<li><strong>4. express中如何获取路由的参数</strong></li>
</ul>
<p>参考答案: /users/:name使用req.params.name来获取; req.body.username则是获得表单传入参数username; express路由支持常用通配符 ?, +, *, and ()</p>
<ul>
<li><strong>5. express response有哪些常用方法</strong></li>
</ul>
<p>参考答案: res.download() 弹出文件下载<br />
res.end() 结束response<br />
res.json() 返回json<br />
res.jsonp() 返回jsonp<br />
res.redirect() 重定向请求<br />
res.render() 渲染模板<br />
res.send() 返回多种形式数据<br />
res.sendFile 返回文件<br />
res.sendStatus() 返回状态</p>
<h2><a id="user-content-其它相关后端常用技术mongodb-redis-apache-nginx等" class="anchor" href="/goto/wzxv" rel="nofollow"></a><a name="user-content-otherBackend"></a>其它相关后端常用技术(MongoDB, Redis, Apache, Nginx等)</h2>
<ul>
<li><strong>1. mongodb有哪些常用优化措施</strong></li>
</ul>
<p>参考答案: 类似传统数据库，索引和分区．</p>
<ul>
<li><strong>2. redis支持哪些功能</strong></li>
</ul>
<p>参考答案: set/get, hset/hget, publish/subscribe, expire</p>
<ul>
<li><strong>3. redis最简单的应用</strong></li>
</ul>
<p>参考答案:</p>
<div class="highlight highlight-source-js">
<pre>    <span class="pl-k">var redis = <span class="pl-c1">require(<span class="pl-s"><span class="pl-pds">"redis"),
        client = redis.createClient();

    client.set("foo_rand000000000000", "some fantastic value");
    client.get("foo_rand000000000000", function (<span class="pl-smi">err, reply) {
        <span class="pl-en">console.log(reply.toString());
    });
    client.end();</span></span></span></span></span></span></pre>
</div>
<ul>
<li><strong>4. apache,nginx有什么区别?</strong></li>
</ul>
<p>参考答案: 二者都是代理服务器，功能类似．apache应用简单，相当广泛．nginx在分布式，静态转发方面比较有优势．</p>
<h2><a id="user-content-常用前端技术html5-css3-jquery等" class="anchor" href="/goto/syd6" rel="nofollow"></a><a name="user-content-otherFrontEnd"></a>常用前端技术(Html5, CSS3, JQuery等)</h2>
<ul>
<li><strong>1. Html5有哪些比较实用新功能</strong></li>
</ul>
<p>参考答案: File API支持本地文件操作; Canvans/SVG支持绘图; 拖拽功能支持; 本地存储支持; 表单多属性验证支持; 原生音频视频支持等</p>
<ul>
<li><strong>2. CSS3/JQuery有哪些学常见选择器</strong></li>
</ul>
<p>参考答案: id, 元素，属性, 值，父子兄弟, 序列等</p>
<ul>
<li><strong>3. JQuery有哪些经典应用</strong></li>
</ul>
<p>参考答案: 文档选择，文档操作，动画, ajax, json, js扩展等.</p>
<h1><a id="user-content-nodejs-设计模式" class="anchor" href="/goto/o8pw" rel="nofollow" aria-hidden="true"></a>node.js 设计模式</h1>
<ul>
<li>HeadFirstDesignPatternInJavascript</li>
<li>HeadFirstDesignPattern是一本非常经典的设计模式入门书籍。可是Javascript由于语言本身的限制，比较难以应用。随着新浏览器和Node.js开始普遍支持ES5, ES6,尤其是对类的支持。设计模式已经变得触手可及，对于大型Node.js项目更是非常必要。 HeadFirstDesignPatternInJavascript正是js版本的设计模式实现。</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>/uncategorized/8689.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5.0（一）部署、控制器、模块、命令行、路由、视图、模板赋值、常用标签、搭建后台首页、搭建登录页、页面跳转与重定向、Request 对象</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7391.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7391.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:44:26 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[Request 对象]]></category>
		<category><![CDATA[命令行]]></category>
		<category><![CDATA[常用标签]]></category>
		<category><![CDATA[控制器]]></category>
		<category><![CDATA[搭建后台首页]]></category>
		<category><![CDATA[搭建登录页]]></category>
		<category><![CDATA[模块]]></category>
		<category><![CDATA[模板赋值]]></category>
		<category><![CDATA[视图]]></category>
		<category><![CDATA[路由]]></category>
		<category><![CDATA[部署]]></category>
		<category><![CDATA[页面跳转与重定向]]></category>
		<guid isPermaLink="false">/?p=7391</guid>

					<description><![CDATA[一、框架概述 1、什么是框架 框架即英文名为Framework,它是许多代码文件的集合，这些代码文件是程序结构 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>一、框架概述</h1>
<h2>1、什么是框架</h2>
<p>框架即英文名为Framework,它是许多代码文件的集合，这些代码文件是程序结构的代码，不是业务代码，里面包含了许多函数、类库(分页类、验证码类、文件上传类、DB类、Image类&#8230;)、设计模式(mvc、单例、AR..)等。</p>
<p>以后使用框架开发项目只需要写业务代码即可。</p>
<p>现在企业中开发模式基本有三种:</p>
<p>从快到慢排序：二次开发(需要修改源码)&#8212;&gt;框架开发&#8212;-&gt;源码开发</p>
<p>源码开发建房子：从0开始，打地基.、浇筑水泥、、</p>
<p>框架开发建房子：相当于毛坯房,各种装修。</p>
<p>源码开发建房子：相当于精装修的房子，只需要拎包入住.</p>
<p>现在企业开发较多的模式属框架开发。</p>
<h2>2、框架开发的好处</h2>
<ul>
<li>框架能节省开发时间</li>
</ul>
<p>每个项目中常用的类库框架都已经封装好，如分页类、图像类,文件上传类等，直接调用即可,非常方便。（减少重复造轮子）</p>
<ul>
<li>利于团队的合作开发</li>
</ul>
<p>因为框架都是mvc设计模式,模块划分清晰，可以帮助我们快速、稳定、高效搭建web应用，从而提高开发效率。</p>
<ul>
<li>使用框架的过程中可以使得我们的注意力全部集中在业务层面，而无需关心程序的底层架构。</li>
</ul>
<h2>3、框架的设计模式(MVC)</h2>
<p>基本现在主流的框架(CI、TP、laravel、YII、zend framework、symfony、cakephp),都是采用单一入口(index.php),且都是采用mvc的设计模式，把一个web应用程序分为三块,控制器、模型、视图。</p>
<p>C-Controller 控制器</p>
<p>主要作用:就是接收用户的请求,在模型和视图之间起一个调度的作用</p>
<p>M-Model 模型</p>
<p>作用:对数据库做增删改查(curd)的</p>
<p>V-View视图</p>
<p>展示模板内容,给用户一个可操作的界面</p>
<p><strong>mvc(框架)形象理解-酒店（难以理解的东西一定要把抽象的东西给生活化）：</strong></p>
<p><img loading="lazy" decoding="async" width="1185" height="451" class="wp-image-7392" src="/wp-content/uploads/2018/06/word-image.png" srcset="/wp-content/uploads/2018/06/word-image.png 1185w, /wp-content/uploads/2018/06/word-image-300x114.png 300w, /wp-content/uploads/2018/06/word-image-768x292.png 768w, /wp-content/uploads/2018/06/word-image-1024x390.png 1024w" sizes="(max-width: 1185px) 100vw, 1185px" /></p>
<h2>常见的php开发框架</h2>
<h3>ThinkPHP框架（TP框架）</h3>
<p>TP框架的logo：</p>
<p><img loading="lazy" decoding="async" width="102" height="70" class="wp-image-7393" src="/wp-content/uploads/2018/06/word-image-1.png" /></p>
<p>主要开发中小型项目</p>
<p>ThinkPHP框架是我们国人开发采用mvc模式设计的一款比较优秀的框架。在我们国内使用量较多，且开发文档也多，方便学习。</p>
<h3>（2）CodeIgniter 框架</h3>
<p>CodeIgniter框架：简称CI框架,</p>
<p>主要开发中小型项目</p>
<p><img loading="lazy" decoding="async" width="823" height="376" class="wp-image-7394" src="/wp-content/uploads/2018/06/word-image-2.png" srcset="/wp-content/uploads/2018/06/word-image-2.png 823w, /wp-content/uploads/2018/06/word-image-2-300x137.png 300w, /wp-content/uploads/2018/06/word-image-2-768x351.png 768w" sizes="(max-width: 823px) 100vw, 823px" /></p>
<h3>YII(易框架)</h3>
<p>YII(简称易框架):主要开发大型的web应用程序:</p>
<p><img loading="lazy" decoding="async" width="818" height="417" class="wp-image-7395" src="/wp-content/uploads/2018/06/word-image-3.png" srcset="/wp-content/uploads/2018/06/word-image-3.png 818w, /wp-content/uploads/2018/06/word-image-3-300x153.png 300w, /wp-content/uploads/2018/06/word-image-3-768x392.png 768w" sizes="(max-width: 818px) 100vw, 818px" /></p>
<h3>Laravel框架</h3>
<p>此框架使用量世界排名第一,有最”优雅”的框架称号。</p>
<p>注：Laravel底层代码很多都是借鉴了SymFony的优点。</p>
<p><img loading="lazy" decoding="async" width="727" height="477" class="wp-image-7396" src="/wp-content/uploads/2018/06/word-image-4.png" srcset="/wp-content/uploads/2018/06/word-image-4.png 727w, /wp-content/uploads/2018/06/word-image-4-300x197.png 300w" sizes="(max-width: 727px) 100vw, 727px" /></p>
<p>&nbsp;</p>
<h3>（5）Zend官方框架</h3>
<p>Zend Framework：php官方提供的框架，非常笨重，主要开发大型的web应用程序。</p>
<p><img loading="lazy" decoding="async" width="729" height="346" class="wp-image-7397" src="/wp-content/uploads/2018/06/word-image-5.png" srcset="/wp-content/uploads/2018/06/word-image-5.png 729w, /wp-content/uploads/2018/06/word-image-5-300x142.png 300w" sizes="(max-width: 729px) 100vw, 729px" /></p>
<h3>（6）Symfony国外框架</h3>
<p><img loading="lazy" decoding="async" width="687" height="480" class="wp-image-7398" src="/wp-content/uploads/2018/06/word-image-6.png" srcset="/wp-content/uploads/2018/06/word-image-6.png 687w, /wp-content/uploads/2018/06/word-image-6-300x210.png 300w" sizes="(max-width: 687px) 100vw, 687px" /></p>
<p>框架只有最合适的，没有最好的，需结合自己的系统业务去选择最合适的。</p>
<p>国内使用最多的框架是TP、laravel、CI。YII框架外企使用较多</p>
<h1>ThinkPHP5框架</h1>
<h2>下载TP5框架</h2>
<p>下载地址：<a href="/goto/rc3y" rel="nofollow">http://www.thinkphp.cn/down.html</a></p>
<p><img loading="lazy" decoding="async" width="671" height="101" class="wp-image-7399" src="/wp-content/uploads/2018/06/word-image-7.png" srcset="/wp-content/uploads/2018/06/word-image-7.png 671w, /wp-content/uploads/2018/06/word-image-7-300x45.png 300w" sizes="(max-width: 671px) 100vw, 671px" /></p>
<p><img loading="lazy" decoding="async" width="192" height="27" class="wp-image-7400" src="/wp-content/uploads/2018/06/word-image-8.png" /></p>
<h2>TP5框架的目录认识</h2>
<p>手册位置：基础&#8211;&gt;目录结构</p>
<ol>
<li>project 应用部署目录</li>
<li>├─application 应用目录（可设置）</li>
<li>│ ├─common 公共模块目录（可更改）</li>
<li>│ ├─index 模块目录(可更改)</li>
<li>│ │ ├─config.php 模块配置文件</li>
<li>│ │ ├─common.php 模块函数文件</li>
<li>│ │ ├─controller 控制器目录</li>
<li>│ │ ├─model 模型目录</li>
<li>│ │ ├─view 视图目录</li>
<li>│ │ └─ &#8230; 更多类库目录</li>
<li>│ ├─command.php 命令行工具配置文件</li>
<li>│ ├─common.php 应用公共（函数）文件</li>
<li>│ ├─config.php 应用（公共）配置文件</li>
<li>│ ├─database.php 数据库配置文件</li>
<li>│ ├─tags.php 应用行为扩展定义文件</li>
<li>│ └─route.php 路由配置文件</li>
<li>├─extend 扩展类库目录（可定义）</li>
<li>├─public WEB 部署目录（对外访问目录）</li>
<li>│ ├─static 静态资源存放目录(css,js,image)</li>
<li>│ ├─index.php 应用入口文件</li>
<li>│ ├─router.php 快速测试文件</li>
<li>│ └─.htaccess 用于 apache 的重写</li>
<li>├─runtime 应用的运行时目录（可写，可设置）</li>
<li>├─vendor 第三方类库目录（Composer）</li>
<li>├─thinkphp 框架系统目录</li>
<li>│ ├─lang 语言包目录</li>
<li>│ ├─library 框架核心类库目录</li>
<li>│ │ ├─think Think 类库包目录</li>
<li>│ │ └─traits 系统 Traits 目录</li>
<li>│ ├─tpl 系统模板目录</li>
<li>│ ├─.htaccess 用于 apache 的重写</li>
<li>│ ├─.travis.yml CI 定义文件</li>
<li>│ ├─base.php 基础定义文件</li>
<li>│ ├─composer.json composer 定义文件</li>
<li>│ ├─console.php 控制台入口文件</li>
<li>│ ├─convention.php 惯例配置文件</li>
<li>│ ├─helper.php 助手函数文件（可选）</li>
<li>│ ├─LICENSE.txt 授权说明文件</li>
<li>│ ├─phpunit.xml 单元测试配置文件</li>
<li>│ ├─README.md README 文件</li>
<li>│ └─start.php 框架引导文件</li>
<li>├─build.php 自动生成定义文件（参考）</li>
<li>├─composer.json composer 定义文件</li>
<li>├─LICENSE.txt 授权说明文件</li>
<li>├─README.md README 文件</li>
<li>├─think 命令行入口文件</li>
</ol>
<p>每个application下面的模块目录都有mvc分层结构：</p>
<p><img loading="lazy" decoding="async" width="380" height="187" class="wp-image-7401" src="/wp-content/uploads/2018/06/word-image-9.png" srcset="/wp-content/uploads/2018/06/word-image-9.png 380w, /wp-content/uploads/2018/06/word-image-9-300x148.png 300w" sizes="(max-width: 380px) 100vw, 380px" /></p>
<p>可参考手册：</p>
<p><img loading="lazy" decoding="async" width="979" height="138" class="wp-image-7402" src="/wp-content/uploads/2018/06/word-image-10.png" srcset="/wp-content/uploads/2018/06/word-image-10.png 979w, /wp-content/uploads/2018/06/word-image-10-300x42.png 300w, /wp-content/uploads/2018/06/word-image-10-768x108.png 768w" sizes="(max-width: 979px) 100vw, 979px" /></p>
<h1>三、使用TP5框架部署项目</h1>
<p>我们是使用ThinkPHP5+ajax+jquery以及和第三方插件结合起来，做一个文章管理系统，掌握怎样使用ThinkPHP5快速开发一个项目。</p>
<h2>配置项目虚拟主机</h2>
<p>主要三个核心步骤：1、使用phpStudy建立虚拟主机 2、设置hosts文件映射 3、重启apache服务器</p>
<p>把框架的文件复制到我们的虚拟主机目录中去：</p>
<p><img loading="lazy" decoding="async" width="652" height="417" class="wp-image-7403" src="/wp-content/uploads/2018/06/word-image-11.png" srcset="/wp-content/uploads/2018/06/word-image-11.png 652w, /wp-content/uploads/2018/06/word-image-11-300x192.png 300w" sizes="(max-width: 652px) 100vw, 652px" /></p>
<ol>
<li>使用phpStudy建立虚拟主机 (www.article.com)</li>
</ol>
<p><img loading="lazy" decoding="async" width="287" height="109" class="wp-image-7404" src="/wp-content/uploads/2018/06/word-image-12.png" /></p>
<p>最终生成的虚拟主机文件（vhosts.conf）配置如下：</p>
<p><img loading="lazy" decoding="async" width="488" height="206" class="wp-image-7405" src="/wp-content/uploads/2018/06/word-image-13.png" srcset="/wp-content/uploads/2018/06/word-image-13.png 488w, /wp-content/uploads/2018/06/word-image-13-300x127.png 300w" sizes="(max-width: 488px) 100vw, 488px" /></p>
<ol>
<li>设置hosts文件映射</li>
</ol>
<p><img loading="lazy" decoding="async" width="374" height="27" class="wp-image-7406" src="/wp-content/uploads/2018/06/word-image-14.png" srcset="/wp-content/uploads/2018/06/word-image-14.png 374w, /wp-content/uploads/2018/06/word-image-14-300x22.png 300w" sizes="(max-width: 374px) 100vw, 374px" /></p>
<ol>
<li>重启apache服务器</li>
</ol>
<h2>2、访问虚拟主机</h2>
<p>输入配置的域名直接访问：</p>
<p><img loading="lazy" decoding="async" width="806" height="368" class="wp-image-7407" src="/wp-content/uploads/2018/06/word-image-15.png" srcset="/wp-content/uploads/2018/06/word-image-15.png 806w, /wp-content/uploads/2018/06/word-image-15-300x137.png 300w, /wp-content/uploads/2018/06/word-image-15-768x351.png 768w" sizes="(max-width: 806px) 100vw, 806px" /></p>
<p>为什么会出现上面的一个笑脸？</p>
<p>答：那是因为受到框架的配置文件application/config.php的影响，默认访问index模块的index控制器的index方法，如下：</p>
<p><img loading="lazy" decoding="async" width="682" height="269" class="wp-image-7408" src="/wp-content/uploads/2018/06/word-image-16.png" srcset="/wp-content/uploads/2018/06/word-image-16.png 682w, /wp-content/uploads/2018/06/word-image-16-300x118.png 300w" sizes="(max-width: 682px) 100vw, 682px" /></p>
<p>可以对index控制器的index方法的内容进行更改：</p>
<p><img loading="lazy" decoding="async" width="668" height="231" class="wp-image-7409" src="/wp-content/uploads/2018/06/word-image-17.png" srcset="/wp-content/uploads/2018/06/word-image-17.png 668w, /wp-content/uploads/2018/06/word-image-17-300x104.png 300w" sizes="(max-width: 668px) 100vw, 668px" /></p>
<p>再次访问如下：</p>
<p><img loading="lazy" decoding="async" width="230" height="70" class="wp-image-7410" src="/wp-content/uploads/2018/06/word-image-18.png" /></p>
<p>注：tp5默认值支持老本tp3的pathinfo模式进行访问。</p>
<p>如：<a href="/goto/sbfh" rel="nofollow">http://域名/index.php/</a><a href="/goto/sbfh" rel="nofollow">模块/控制器/方法名</a><a href="/goto/sbfh" rel="nofollow">/参数1/值1/参数2/值2/</a></p>
<p>例：访问index模块的index 控制器的index方法</p>
<p>http://域名/index.php/index/index/index/参数1/值1/参数2/值2/</p>
<h2>3、响应输出</h2>
<p>控制器的所有操作方法都是return返回而不是直接输出，系统会调用Response::send方法将最终的应用返回的数据输出到页面或者客户端，并自动转换成default_return_type参数配置的格式。所以，应用执行的数据输出只需要返回一个正常的PHP数据即可。</p>
<p>tp5也是建议统一使用return返回数据，而不是echo输出，如非必要，请不要使用exit或者die中断执行。</p>
<p><img loading="lazy" decoding="async" width="509" height="59" class="wp-image-7411" src="/wp-content/uploads/2018/06/word-image-19.png" srcset="/wp-content/uploads/2018/06/word-image-19.png 509w, /wp-content/uploads/2018/06/word-image-19-300x35.png 300w" sizes="(max-width: 509px) 100vw, 509px" /></p>
<h1>四、控制器</h1>
<h2>控制器的作用</h2>
<p>C：Controller</p>
<p>作用：主要是接受用户的请求，在模型和视图之间起调度的作用。</p>
<h2>创建控制器</h2>
<h3>（1）修改控制器后缀</h3>
<p>由于国人命名的习惯，我们可以通过以下配置文件给控制器文件名加个Controller后缀。</p>
<p>打开配置文件，[项目目录]/application/config.php，做如下修改：</p>
<p><img loading="lazy" decoding="async" width="999" height="207" class="wp-image-7412" src="/wp-content/uploads/2018/06/word-image-20.png" srcset="/wp-content/uploads/2018/06/word-image-20.png 999w, /wp-content/uploads/2018/06/word-image-20-300x62.png 300w, /wp-content/uploads/2018/06/word-image-20-768x159.png 768w" sizes="(max-width: 999px) 100vw, 999px" /></p>
<h3>创建控制器语法</h3>
<p>语法规则：</p>
<p>控制器类名：控制器名+Controller</p>
<p>控制器文件名：控制器名+Controller.php</p>
<p>控制器文件所在路径：application/模块名/controller/</p>
<p>如在index模块下定义一个Test控制器：</p>
<p>控制器类名： TestController</p>
<p>控制器类文件名： TestController.php</p>
<p>文件定义位置：index/controller/TestController.php</p>
<p>注：类名首字母大写</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="683" height="298" class="wp-image-7413" src="/wp-content/uploads/2018/06/word-image-21.png" srcset="/wp-content/uploads/2018/06/word-image-21.png 683w, /wp-content/uploads/2018/06/word-image-21-300x131.png 300w" sizes="(max-width: 683px) 100vw, 683px" /></p>
<p>访问：</p>
<p><img loading="lazy" decoding="async" width="499" height="64" class="wp-image-7414" src="/wp-content/uploads/2018/06/word-image-22.png" srcset="/wp-content/uploads/2018/06/word-image-22.png 499w, /wp-content/uploads/2018/06/word-image-22-300x38.png 300w" sizes="(max-width: 499px) 100vw, 499px" /></p>
<h3>访问控制器</h3>
<p>1、可以通过tp3老版本的pathInfo模式进行访问。</p>
<p><a href="/goto/ghx2" rel="nofollow">http://网址/index.php/分组/控制器名称/操作方法名称</a></p>
<p>如访问Index模块的index控制器的test1方法</p>
<p><img loading="lazy" decoding="async" width="795" height="74" class="wp-image-7415" src="/wp-content/uploads/2018/06/word-image-23.png" srcset="/wp-content/uploads/2018/06/word-image-23.png 795w, /wp-content/uploads/2018/06/word-image-23-300x28.png 300w, /wp-content/uploads/2018/06/word-image-23-768x71.png 768w" sizes="(max-width: 795px) 100vw, 795px" /></p>
<p>2、也可以把index.php入口文件给隐藏掉，变为下边的路由形式：</p>
<p><a href="/goto/ghx2" rel="nofollow">http://网址/分组/控制器名称/操作方法名称</a></p>
<p>省去index.php入口访问，修改项目的重写文件.htaaccess。</p>
<p>第一步：文件位置：[项目根目录]/Public/.htaccess ,做如下修改：</p>
<p><img loading="lazy" decoding="async" width="514" height="211" class="wp-image-7416" src="/wp-content/uploads/2018/06/word-image-24.png" srcset="/wp-content/uploads/2018/06/word-image-24.png 514w, /wp-content/uploads/2018/06/word-image-24-300x123.png 300w" sizes="(max-width: 514px) 100vw, 514px" /></p>
<p>(注：上图在index.php后边加”?”号)</p>
<p>重写文件.htaccsee解释：</p>
<p>&lt;IfModule mod_rewrite.c&gt;</p>
<p>Options +FollowSymlinks -Multiviews</p>
<p>RewriteEngine On #开启重写规则</p>
<p>RewriteCond %{REQUEST_FILENAME} !-d #如果请求的不是一个目录（-d 代表目录）</p>
<p>RewriteCond %{REQUEST_FILENAME} !-f #且如果请求的不是一个文件（-f 代表文件）</p>
<p>RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] #上面两个条件都不满足，执行RewriteRule重写规则</p>
<p>&lt;/IfModule&gt;</p>
<p>重写规则: RewriteRule 虚拟规则（正则写） 服务器真实文件路径</p>
<p>即用户输入的域名后面的规则若满足虚拟规则，就会访问对应的真实文件。</p>
<p>第二步：修改虚拟主机vhosts.conf的配置：加上AllowOverride All ，默认phpstudy创建的虚拟主机自带这一行。</p>
<p><img loading="lazy" decoding="async" width="558" height="213" class="wp-image-7417" src="/wp-content/uploads/2018/06/word-image-25.png" srcset="/wp-content/uploads/2018/06/word-image-25.png 558w, /wp-content/uploads/2018/06/word-image-25-300x115.png 300w" sizes="(max-width: 558px) 100vw, 558px" /></p>
<p>第三步。再去httpd.conf开启重写文件：</p>
<p><img loading="lazy" decoding="async" width="747" height="169" class="wp-image-7418" src="/wp-content/uploads/2018/06/word-image-26.png" srcset="/wp-content/uploads/2018/06/word-image-26.png 747w, /wp-content/uploads/2018/06/word-image-26-300x68.png 300w" sizes="(max-width: 747px) 100vw, 747px" /></p>
<p>重启apache服务器，省去入口文件index.php进行访问:</p>
<p><img loading="lazy" decoding="async" width="352" height="74" class="wp-image-7419" src="/wp-content/uploads/2018/06/word-image-27.png" srcset="/wp-content/uploads/2018/06/word-image-27.png 352w, /wp-content/uploads/2018/06/word-image-27-300x63.png 300w" sizes="(max-width: 352px) 100vw, 352px" /></p>
<h3>开启调试模式</h3>
<p>为了在开发过程中，开发者能够及时看到详细的错误信息，我们在开发阶段可以把以下config配置文件中的app_debug配置设置为true,</p>
<p><img loading="lazy" decoding="async" width="700" height="173" class="wp-image-7420" src="/wp-content/uploads/2018/06/word-image-28.png" srcset="/wp-content/uploads/2018/06/word-image-28.png 700w, /wp-content/uploads/2018/06/word-image-28-300x74.png 300w" sizes="(max-width: 700px) 100vw, 700px" /></p>
<p>访问一个不存在的方法,会报详细的错误。</p>
<p><img loading="lazy" decoding="async" width="955" height="167" class="wp-image-7421" src="/wp-content/uploads/2018/06/word-image-29.png" srcset="/wp-content/uploads/2018/06/word-image-29.png 955w, /wp-content/uploads/2018/06/word-image-29-300x52.png 300w, /wp-content/uploads/2018/06/word-image-29-768x134.png 768w" sizes="(max-width: 955px) 100vw, 955px" /></p>
<p>若设置为false,则会出现友好的提示：</p>
<p><img loading="lazy" decoding="async" width="461" height="147" class="wp-image-7422" src="/wp-content/uploads/2018/06/word-image-30.png" srcset="/wp-content/uploads/2018/06/word-image-30.png 461w, /wp-content/uploads/2018/06/word-image-30-300x96.png 300w" sizes="(max-width: 461px) 100vw, 461px" /></p>
<p>所以，项目上线后，我们要把此配置改为false。不要让用户看到我们网站报错。</p>
<h1>五、项目分组（模块）</h1>
<h2>1、创建分组</h2>
<p>一个项目中一般都有Home、Admin分组，即前台和后台，那对应框架中就是一个具体的文件夹，每个项目文件夹都有对应的控制器、模型、视图对应的文件夹，tp5框架中默认有一个分组index。</p>
<p>我们只需要把index分组复制一份改名（如admin）放在Application目录下即可，同时修改对应类所在分组的命名空间即可。</p>
<p><img loading="lazy" decoding="async" width="689" height="231" class="wp-image-7423" src="/wp-content/uploads/2018/06/word-image-31.png" srcset="/wp-content/uploads/2018/06/word-image-31.png 689w, /wp-content/uploads/2018/06/word-image-31-300x101.png 300w" sizes="(max-width: 689px) 100vw, 689px" /></p>
<p>也需要改对应类的命名空间：</p>
<p><img loading="lazy" decoding="async" width="808" height="332" class="wp-image-7424" src="/wp-content/uploads/2018/06/word-image-32.png" srcset="/wp-content/uploads/2018/06/word-image-32.png 808w, /wp-content/uploads/2018/06/word-image-32-300x123.png 300w, /wp-content/uploads/2018/06/word-image-32-768x316.png 768w" sizes="(max-width: 808px) 100vw, 808px" /></p>
<p>访问如下：</p>
<p><img loading="lazy" decoding="async" width="454" height="64" class="wp-image-7425" src="/wp-content/uploads/2018/06/word-image-33.png" srcset="/wp-content/uploads/2018/06/word-image-33.png 454w, /wp-content/uploads/2018/06/word-image-33-300x42.png 300w" sizes="(max-width: 454px) 100vw, 454px" /></p>
<h2>2、默认分组的设置</h2>
<p>需修改框架的application/config.php的配置文件，如默认访问admin分组的index控制器的index方法，做如下修改：</p>
<p><img loading="lazy" decoding="async" width="834" height="301" class="wp-image-7426" src="/wp-content/uploads/2018/06/word-image-34.png" srcset="/wp-content/uploads/2018/06/word-image-34.png 834w, /wp-content/uploads/2018/06/word-image-34-300x108.png 300w, /wp-content/uploads/2018/06/word-image-34-768x277.png 768w" sizes="(max-width: 834px) 100vw, 834px" /></p>
<p>直接输入域名访问的则是admin模块下的index控制器的index方法：</p>
<p><img loading="lazy" decoding="async" width="416" height="103" class="wp-image-7427" src="/wp-content/uploads/2018/06/word-image-35.png" srcset="/wp-content/uploads/2018/06/word-image-35.png 416w, /wp-content/uploads/2018/06/word-image-35-300x74.png 300w" sizes="(max-width: 416px) 100vw, 416px" /></p>
<h2>3、分组的访问权限控制</h2>
<p>需修改框架的application/config.php的配置文件：</p>
<p><img loading="lazy" decoding="async" width="612" height="78" class="wp-image-7428" src="/wp-content/uploads/2018/06/word-image-36.png" srcset="/wp-content/uploads/2018/06/word-image-36.png 612w, /wp-content/uploads/2018/06/word-image-36-300x38.png 300w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>上图是设置禁止访问common和index分组。</p>
<p>再次访问index模块，会报错。</p>
<p><img loading="lazy" decoding="async" width="625" height="210" class="wp-image-7429" src="/wp-content/uploads/2018/06/word-image-37.png" srcset="/wp-content/uploads/2018/06/word-image-37.png 625w, /wp-content/uploads/2018/06/word-image-37-300x101.png 300w" sizes="(max-width: 625px) 100vw, 625px" /></p>
<h1>六、【了解】命令行操作</h1>
<h2>命令行创建分组</h2>
<p>创建文件application/build.php并填充内容，可以参考根目录 build.php</p>
<p>[项目根目录] &gt; php think build</p>
<p>创建application/build.php并填充如下内容：</p>
<p><img loading="lazy" decoding="async" width="1209" height="397" class="wp-image-7430" src="/wp-content/uploads/2018/06/word-image-38.png" srcset="/wp-content/uploads/2018/06/word-image-38.png 1209w, /wp-content/uploads/2018/06/word-image-38-300x99.png 300w, /wp-content/uploads/2018/06/word-image-38-768x252.png 768w, /wp-content/uploads/2018/06/word-image-38-1024x336.png 1024w" sizes="(max-width: 1209px) 100vw, 1209px" /></p>
<p>执行命令</p>
<p><img loading="lazy" decoding="async" width="365" height="79" class="wp-image-7431" src="/wp-content/uploads/2018/06/word-image-39.png" srcset="/wp-content/uploads/2018/06/word-image-39.png 365w, /wp-content/uploads/2018/06/word-image-39-300x65.png 300w" sizes="(max-width: 365px) 100vw, 365px" /></p>
<p>创建分组的效果</p>
<h2>命令行创建控制器</h2>
<p>[项目根目录] &gt; php think make:controller 分组/名称</p>
<p>注：不写分组名会直接创建在common分组中</p>
<p>例：在Common中生成一个Demo的控制器</p>
<p><img loading="lazy" decoding="async" width="433" height="44" class="wp-image-7432" src="/wp-content/uploads/2018/06/word-image-40.png" srcset="/wp-content/uploads/2018/06/word-image-40.png 433w, /wp-content/uploads/2018/06/word-image-40-300x30.png 300w" sizes="(max-width: 433px) 100vw, 433px" /></p>
<p>生成如下所示：</p>
<p><img loading="lazy" decoding="async" width="881" height="331" class="wp-image-7433" src="/wp-content/uploads/2018/06/word-image-41.png" srcset="/wp-content/uploads/2018/06/word-image-41.png 881w, /wp-content/uploads/2018/06/word-image-41-300x113.png 300w, /wp-content/uploads/2018/06/word-image-41-768x289.png 768w" sizes="(max-width: 881px) 100vw, 881px" /></p>
<p>例如下述，要给index分组创建UserController.php控制器文件</p>
<p>[项目根目录] &gt; php think make:controller index/User</p>
<p>命令如下；</p>
<p><img loading="lazy" decoding="async" width="494" height="48" class="wp-image-7434" src="/wp-content/uploads/2018/06/word-image-42.png" srcset="/wp-content/uploads/2018/06/word-image-42.png 494w, /wp-content/uploads/2018/06/word-image-42-300x29.png 300w" sizes="(max-width: 494px) 100vw, 494px" /></p>
<p>生成的文件：</p>
<p><img loading="lazy" decoding="async" width="817" height="341" class="wp-image-7435" src="/wp-content/uploads/2018/06/word-image-43.png" srcset="/wp-content/uploads/2018/06/word-image-43.png 817w, /wp-content/uploads/2018/06/word-image-43-300x125.png 300w, /wp-content/uploads/2018/06/word-image-43-768x321.png 768w" sizes="(max-width: 817px) 100vw, 817px" /></p>
<h1>七、使用路由访问</h1>
<p>老版本TP3.2多种访问模式（了解）：</p>
<ul>
<li>pathinfo模式（默认形式,,重点掌握）：http://域名/index.php/模块/控制器名/方法名/参数名/参数值/参数名/参数值&#8230;</li>
</ul>
<p><img loading="lazy" decoding="async" width="578" height="38" class="wp-image-7436" src="/wp-content/uploads/2018/06/word-image-44.png" srcset="/wp-content/uploads/2018/06/word-image-44.png 578w, /wp-content/uploads/2018/06/word-image-44-300x20.png 300w" sizes="(max-width: 578px) 100vw, 578px" /></p>
<ul>
<li>普通模式（get形式）：http://域名/index.php?m=模块&amp;c=控制器名&amp;a=方法名&amp;参数名=参数值&#8230;</li>
</ul>
<p><img loading="lazy" decoding="async" width="605" height="79" class="wp-image-7437" src="/wp-content/uploads/2018/06/word-image-45.png" srcset="/wp-content/uploads/2018/06/word-image-45.png 605w, /wp-content/uploads/2018/06/word-image-45-300x39.png 300w" sizes="(max-width: 605px) 100vw, 605px" /></p>
<ul>
<li>rewrite模式（隐藏入口文件）：<a href="/goto/98sz" rel="nofollow">http://域名/模块/控制器名/方法名/参数名/参数值/参数名/参数值&#8230;</a></li>
</ul>
<p><img loading="lazy" decoding="async" width="515" height="82" class="wp-image-7438" src="/wp-content/uploads/2018/06/word-image-46.png" srcset="/wp-content/uploads/2018/06/word-image-46.png 515w, /wp-content/uploads/2018/06/word-image-46-300x48.png 300w" sizes="(max-width: 515px) 100vw, 515px" /></p>
<ul>
<li>兼容模式：http://域名/inde.php?s=/模块/控制器名/方法名/参数名/参数值&#8230;</li>
</ul>
<p><img loading="lazy" decoding="async" width="534" height="83" class="wp-image-7439" src="/wp-content/uploads/2018/06/word-image-47.png" srcset="/wp-content/uploads/2018/06/word-image-47.png 534w, /wp-content/uploads/2018/06/word-image-47-300x47.png 300w" sizes="(max-width: 534px) 100vw, 534px" /></p>
<p>上面的四种模式在tp5默认都是支持的。其在tp5框架中还可以单独定义路由规则来访问某个控制器中的某个方法。</p>
<p>只要配置文件config.php中开启路由功能，访问的时候就会经过路由规则，根据定义的路由规则从而访问到某个控制器中的方法。</p>
<p>路由图解：</p>
<p><img loading="lazy" decoding="async" width="697" height="91" class="wp-image-7440" src="/wp-content/uploads/2018/06/word-image-48.png" srcset="/wp-content/uploads/2018/06/word-image-48.png 697w, /wp-content/uploads/2018/06/word-image-48-300x39.png 300w" sizes="(max-width: 697px) 100vw, 697px" /></p>
<ol>
<li>开启路由，修改application/config.php配置文件</li>
</ol>
<p>&#8216;url_route_on&#8217; =&gt; true, // 开启路由</p>
<p>&#8216;url_route_must&#8217; =&gt; true, // 必须使用路由(即不能使用之前的pathinfo模式访问)</p>
<p>注：若url_route_must设置为true,就不就可以通过上面四种模式来访问，只能通过定义的路由规则访问。</p>
<p>2、定义路由规则，定义在application/route.php文件中</p>
<p>Route::rule(&#8216;路由表达式&#8217;,&#8217;路由地址&#8217;,&#8217;请求类型&#8217;,&#8217;路由参数(数组)&#8217;,&#8217;变量规则(数组)&#8217;);</p>
<p>说明：</p>
<p><strong>路由表达式</strong>：静态地址、动态地址、可选动态地址</p>
<p><strong>路由地址</strong>：表示路由表达式最终需要路由到的地址，有多种定义方式，常用的是”模块/控制器/操作?额外参数1=值1&amp;额外参数2=值2”形式</p>
<p><strong>请求类型</strong>：GET、POST 必须是大写的</p>
<p><strong>路由参数</strong>：</p>
<p>method:请求类型</p>
<p>ext:允许的后缀</p>
<p>deny_ext:禁止的访问后缀</p>
<p>domain:允许什么样的域名访问有效</p>
<p>https:检测是否是https请求</p>
<p>before_behavior:行为发生前，进行路由检查</p>
<p>after_behavior:行为发生后，要执行的动作</p>
<p>&#8230;</p>
<p>详情参考：手册路由&#8211;&gt;路由参数</p>
<p>变量规则：检查传递的变量是否符合某个(正则)规则,规则可以通过正则定义</p>
<p>例如规则：</p>
<p>Route::rule(‘login’,’home/User/login’,’GET’,[‘ext’=&gt;’html’]);</p>
<p>访问：<a href="/goto/dzl6" rel="nofollow">http://servername/index.php/login</a>.html</p>
<p>路由到：<a href="/goto/5h9l" rel="nofollow">http://servername/index.php/home/User/login</a></p>
<p>Route::rule(‘login/:id’,’home/User/login’,’GET’,[‘ext’=&gt;’html’],[‘id’=&gt;’\d+’]);</p>
<p>访问：<a href="/goto/dzl6" rel="nofollow">http://servername/index.php/login</a>/101.html</p>
<p>路由到：<a href="/goto/5h9l" rel="nofollow">http://servername/index.php/home/User/login</a>/id/101</p>
<p>Route::rule(‘login/:id/:name’,’home/User/login’,’GET’,[‘ext’=&gt;’html’],[‘id’=&gt;’\d+’,’name’=&gt;’[a-zA-Z]+’]);</p>
<p>访问：<a href="/goto/dzl6" rel="nofollow">http://servername/index.php/login</a>/101/tom.html</p>
<p>路由到：</p>
<p><a href="/goto/5h9l" rel="nofollow">http://servername/index.php/home/User/login</a>/id/101/name/tom</p>
<p>也可以像下边这样定义:</p>
<p>Route::get(&#8216;路由表达式&#8217;,&#8217;路由地址&#8217;,&#8217;路由参数(数组)&#8217;,&#8217;变量规则(数组)&#8217;);</p>
<p>Route::post(&#8216;路由表达式&#8217;,&#8217;路由地址&#8217;,&#8217;路由参数(数组)&#8217;,&#8217;变量规则(数组)&#8217;);</p>
<p>如一个控制器中的方法在路由规则中没有定义则是不允许被访问，报以下错误：</p>
<p><img loading="lazy" decoding="async" width="701" height="144" class="wp-image-7441" src="/wp-content/uploads/2018/06/word-image-49.png" srcset="/wp-content/uploads/2018/06/word-image-49.png 701w, /wp-content/uploads/2018/06/word-image-49-300x62.png 300w" sizes="(max-width: 701px) 100vw, 701px" /></p>
<p>解决办法，把application/config.php文件中的以下配置改为false,就说明路由规则和pathinfo形式两者都可以进行访问。</p>
<p>&#8216;url_route_must&#8217; =&gt; false, // 是否强制使用路由</p>
<p>在application/route.php中定义路由规则：</p>
<p><img loading="lazy" decoding="async" width="1171" height="392" class="wp-image-7442" src="/wp-content/uploads/2018/06/word-image-50.png" srcset="/wp-content/uploads/2018/06/word-image-50.png 1171w, /wp-content/uploads/2018/06/word-image-50-300x100.png 300w, /wp-content/uploads/2018/06/word-image-50-768x257.png 768w, /wp-content/uploads/2018/06/word-image-50-1024x343.png 1024w" sizes="(max-width: 1171px) 100vw, 1171px" /></p>
<p>访问如下：</p>
<p><img loading="lazy" decoding="async" width="323" height="71" class="wp-image-7443" src="/wp-content/uploads/2018/06/word-image-51.png" srcset="/wp-content/uploads/2018/06/word-image-51.png 323w, /wp-content/uploads/2018/06/word-image-51-300x66.png 300w" sizes="(max-width: 323px) 100vw, 323px" /></p>
<p><img loading="lazy" decoding="async" width="328" height="64" class="wp-image-7444" src="/wp-content/uploads/2018/06/word-image-52.png" srcset="/wp-content/uploads/2018/06/word-image-52.png 328w, /wp-content/uploads/2018/06/word-image-52-300x59.png 300w" sizes="(max-width: 328px) 100vw, 328px" /></p>
<p><img loading="lazy" decoding="async" width="317" height="66" class="wp-image-7445" src="/wp-content/uploads/2018/06/word-image-53.png" srcset="/wp-content/uploads/2018/06/word-image-53.png 317w, /wp-content/uploads/2018/06/word-image-53-300x62.png 300w" sizes="(max-width: 317px) 100vw, 317px" /></p>
<h1>展示视图</h1>
<p>语法：控制器中调用fetch方法</p>
<p>return $this -&gt; fetch(模块@控制器/操作);</p>
<p>注意：</p>
<p>控制器要想正常调用fetch方法，则必须继承Controller类：use think\Controller</p>
<p>fetch()具体有下述5种用法：</p>
<ul>
<li>调用：view下当前控制器名/当前操作名.html模版文件</li>
</ul>
<p>return $this -&gt; fetch();</p>
<ul>
<li>调用：view下当前控制器的/add.html模版文件</li>
</ul>
<p>return $this -&gt; fetch(‘add’);</p>
<ul>
<li>找到view下边user目录的login.html模版文件[跨控制器]</li>
</ul>
<p>return $this -&gt; fetch(&#8216;user/login&#8217;);</p>
<ul>
<li>找到admin分组view目录的manager下边的login.html模版文件[跨分组]</li>
</ul>
<p>return $this -&gt; fetch(&#8216;admin@manager/login&#8217;);</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="879" height="322" class="wp-image-7446" src="/wp-content/uploads/2018/06/word-image-54.png" srcset="/wp-content/uploads/2018/06/word-image-54.png 879w, /wp-content/uploads/2018/06/word-image-54-300x110.png 300w, /wp-content/uploads/2018/06/word-image-54-768x281.png 768w" sizes="(max-width: 879px) 100vw, 879px" /></p>
<p>结果：</p>
<p><img loading="lazy" decoding="async" width="428" height="86" class="wp-image-7447" src="/wp-content/uploads/2018/06/word-image-55.png" srcset="/wp-content/uploads/2018/06/word-image-55.png 428w, /wp-content/uploads/2018/06/word-image-55-300x60.png 300w" sizes="(max-width: 428px) 100vw, 428px" /></p>
<h1>九、模板赋值</h1>
<p>语法：在控制器调用assign方法</p>
<ol>
<li>public function index()</li>
<li>{</li>
<li>// 模板变量赋值</li>
<li>$this-&gt;assign(&#8216;name&#8217;,&#8217;ThinkPHP&#8217;);</li>
<li>$this-&gt;assign(&#8217;email&#8217;,&#8217;thinkphp@qq.com&#8217;);</li>
<li>// 或者批量赋值</li>
<li>$this-&gt;assign([</li>
<li>&#8216;name&#8217; =&gt; &#8216;ThinkPHP&#8217;,</li>
<li>&#8217;email&#8217; =&gt; &#8216;thinkphp@qq.com&#8217;</li>
<li>]);</li>
<li>// 模板输出</li>
<li>return $this-&gt;fetch(&#8216;index&#8217;);</li>
<li>}</li>
</ol>
<p>或者把模板变量直接传递给fetch方法：</p>
<ol>
<li>public function index()</li>
<li>{</li>
<li>return $this-&gt;fetch(&#8216;index&#8217;, [</li>
<li>&#8216;name&#8217; =&gt; &#8216;ThinkPHP&#8217;,</li>
<li>&#8217;email&#8217; =&gt; &#8216;thinkphp@qq.com&#8217;</li>
<li>]);</li>
<li>}</li>
</ol>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="611" height="174" class="wp-image-7448" src="/wp-content/uploads/2018/06/word-image-56.png" srcset="/wp-content/uploads/2018/06/word-image-56.png 611w, /wp-content/uploads/2018/06/word-image-56-300x85.png 300w" sizes="(max-width: 611px) 100vw, 611px" /></p>
<p>模板中显示：</p>
<p><img loading="lazy" decoding="async" width="392" height="94" class="wp-image-7449" src="/wp-content/uploads/2018/06/word-image-57.png" srcset="/wp-content/uploads/2018/06/word-image-57.png 392w, /wp-content/uploads/2018/06/word-image-57-300x72.png 300w" sizes="(max-width: 392px) 100vw, 392px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="414" height="132" class="wp-image-7450" src="/wp-content/uploads/2018/06/word-image-58.png" srcset="/wp-content/uploads/2018/06/word-image-58.png 414w, /wp-content/uploads/2018/06/word-image-58-300x96.png 300w" sizes="(max-width: 414px) 100vw, 414px" /></p>
<p>建议使用如下方式，分配模板变量：<br />
<img loading="lazy" decoding="async" width="735" height="212" class="wp-image-7451" src="/wp-content/uploads/2018/06/word-image-59.png" srcset="/wp-content/uploads/2018/06/word-image-59.png 735w, /wp-content/uploads/2018/06/word-image-59-300x87.png 300w" sizes="(max-width: 735px) 100vw, 735px" /></p>
<p>模板中显示：</p>
<p><img loading="lazy" decoding="async" width="630" height="265" class="wp-image-7452" src="/wp-content/uploads/2018/06/word-image-60.png" srcset="/wp-content/uploads/2018/06/word-image-60.png 630w, /wp-content/uploads/2018/06/word-image-60-300x126.png 300w" sizes="(max-width: 630px) 100vw, 630px" /></p>
<h1>十、模板常用标签</h1>
<h2>volist标签</h2>
<p>作用：主要用来遍历数组</p>
<p>语法：</p>
<p><img loading="lazy" decoding="async" width="966" height="275" class="wp-image-7453" src="/wp-content/uploads/2018/06/word-image-61.png" srcset="/wp-content/uploads/2018/06/word-image-61.png 966w, /wp-content/uploads/2018/06/word-image-61-300x85.png 300w, /wp-content/uploads/2018/06/word-image-61-768x219.png 768w" sizes="(max-width: 966px) 100vw, 966px" /></p>
<p>Volist标签的name属性表示模板赋值的变量名称，因此不可随意在模板文件中改变。id表示当前的循环变量，可以随意指定，但确保不要和name属性值冲突。</p>
<p>代码如下：</p>
<p>控制器对模板赋值：</p>
<p><img loading="lazy" decoding="async" width="706" height="394" class="wp-image-7454" src="/wp-content/uploads/2018/06/word-image-62.png" srcset="/wp-content/uploads/2018/06/word-image-62.png 706w, /wp-content/uploads/2018/06/word-image-62-300x167.png 300w" sizes="(max-width: 706px) 100vw, 706px" /></p>
<p>模板遍历：</p>
<p><img loading="lazy" decoding="async" width="802" height="375" class="wp-image-7455" src="/wp-content/uploads/2018/06/word-image-63.png" srcset="/wp-content/uploads/2018/06/word-image-63.png 802w, /wp-content/uploads/2018/06/word-image-63-300x140.png 300w, /wp-content/uploads/2018/06/word-image-63-768x359.png 768w" sizes="(max-width: 802px) 100vw, 802px" /></p>
<p>效果：<br />
<img loading="lazy" decoding="async" width="448" height="272" class="wp-image-7456" src="/wp-content/uploads/2018/06/word-image-64.png" srcset="/wp-content/uploads/2018/06/word-image-64.png 448w, /wp-content/uploads/2018/06/word-image-64-300x182.png 300w" sizes="(max-width: 448px) 100vw, 448px" /></p>
<p>循环数组序号（标号）：</p>
<p><img loading="lazy" decoding="async" width="809" height="253" class="wp-image-7457" src="/wp-content/uploads/2018/06/word-image-65.png" srcset="/wp-content/uploads/2018/06/word-image-65.png 809w, /wp-content/uploads/2018/06/word-image-65-300x94.png 300w, /wp-content/uploads/2018/06/word-image-65-768x240.png 768w" sizes="(max-width: 809px) 100vw, 809px" /></p>
<p>注：如果不知道key属性，默认{$key}从0开始，所以需要加1{$key+1}</p>
<h2>比较标签</h2>
<p>参考手册：</p>
<p><img loading="lazy" decoding="async" width="788" height="449" class="wp-image-7458" src="/wp-content/uploads/2018/06/word-image-66.png" srcset="/wp-content/uploads/2018/06/word-image-66.png 788w, /wp-content/uploads/2018/06/word-image-66-300x171.png 300w, /wp-content/uploads/2018/06/word-image-66-768x438.png 768w" sizes="(max-width: 788px) 100vw, 788px" /></p>
<p>使用范例：</p>
<p><img loading="lazy" decoding="async" width="387" height="123" class="wp-image-7459" src="/wp-content/uploads/2018/06/word-image-67.png" srcset="/wp-content/uploads/2018/06/word-image-67.png 387w, /wp-content/uploads/2018/06/word-image-67-300x95.png 300w" sizes="(max-width: 387px) 100vw, 387px" /></p>
<p>代码如下：</p>
<p>模板赋值遍历：</p>
<p><img loading="lazy" decoding="async" width="600" height="50" class="wp-image-7460" src="/wp-content/uploads/2018/06/word-image-68.png" srcset="/wp-content/uploads/2018/06/word-image-68.png 600w, /wp-content/uploads/2018/06/word-image-68-300x25.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></p>
<p>模板判断：</p>
<p><img loading="lazy" decoding="async" width="326" height="146" class="wp-image-7461" src="/wp-content/uploads/2018/06/word-image-69.png" srcset="/wp-content/uploads/2018/06/word-image-69.png 326w, /wp-content/uploads/2018/06/word-image-69-300x134.png 300w" sizes="(max-width: 326px) 100vw, 326px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="165" height="83" class="wp-image-7462" src="/wp-content/uploads/2018/06/word-image-70.png" /></p>
<h2>php标签</h2>
<p>如果模板标签太多记不住，这里可以使用php标签统一进行一些代码的编写：</p>
<p><img loading="lazy" decoding="async" width="716" height="258" class="wp-image-7463" src="/wp-content/uploads/2018/06/word-image-71.png" srcset="/wp-content/uploads/2018/06/word-image-71.png 716w, /wp-content/uploads/2018/06/word-image-71-300x108.png 300w" sizes="(max-width: 716px) 100vw, 716px" /></p>
<p>例1：代码如下：</p>
<p><img loading="lazy" decoding="async" width="885" height="546" class="wp-image-7464" src="/wp-content/uploads/2018/06/word-image-72.png" srcset="/wp-content/uploads/2018/06/word-image-72.png 885w, /wp-content/uploads/2018/06/word-image-72-300x185.png 300w, /wp-content/uploads/2018/06/word-image-72-768x474.png 768w" sizes="(max-width: 885px) 100vw, 885px" /></p>
<p>例2：代码如下：</p>
<p>控制器赋值：</p>
<p><img loading="lazy" decoding="async" width="512" height="63" class="wp-image-7465" src="/wp-content/uploads/2018/06/word-image-73.png" srcset="/wp-content/uploads/2018/06/word-image-73.png 512w, /wp-content/uploads/2018/06/word-image-73-300x37.png 300w" sizes="(max-width: 512px) 100vw, 512px" /></p>
<p>模板获取：</p>
<p><img loading="lazy" decoding="async" width="549" height="191" class="wp-image-7466" src="/wp-content/uploads/2018/06/word-image-74.png" srcset="/wp-content/uploads/2018/06/word-image-74.png 549w, /wp-content/uploads/2018/06/word-image-74-300x104.png 300w" sizes="(max-width: 549px) 100vw, 549px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="100" height="77" class="wp-image-7467" src="/wp-content/uploads/2018/06/word-image-75.png" /></p>
<h2>include包含标签</h2>
<p><strong>作用</strong>：</p>
<p>一般网站页面的头部或尾部的网页效果都是一样的，我们就可以把这些网页的代码抽离出来放在一个html文件中，需要使用这些文件的时候，在模板中用include标签引入即可，从而提高代码的复用性。</p>
<p><strong>include语法：</strong></p>
<p><img loading="lazy" decoding="async" width="482" height="57" class="wp-image-7468" src="/wp-content/uploads/2018/06/word-image-76.png" srcset="/wp-content/uploads/2018/06/word-image-76.png 482w, /wp-content/uploads/2018/06/word-image-76-300x35.png 300w" sizes="(max-width: 482px) 100vw, 482px" /></p>
<p>注意：file的路径是从当前模块的view目录下开始找起。</p>
<p>如：有一个header.html模板，其所在路径为：Admin/view/public/header.html</p>
<p>在模板中引入此文件： &lt;include file=”public/header” /&gt;</p>
<p><strong>代码如下：</strong></p>
<p>控制器输出模板：</p>
<p><img loading="lazy" decoding="async" width="567" height="202" class="wp-image-7469" src="/wp-content/uploads/2018/06/word-image-77.png" srcset="/wp-content/uploads/2018/06/word-image-77.png 567w, /wp-content/uploads/2018/06/word-image-77-300x107.png 300w" sizes="(max-width: 567px) 100vw, 567px" /></p>
<p>在模板中引入公共的文件：</p>
<p><img loading="lazy" decoding="async" width="1019" height="353" class="wp-image-7470" src="/wp-content/uploads/2018/06/word-image-78.png" srcset="/wp-content/uploads/2018/06/word-image-78.png 1019w, /wp-content/uploads/2018/06/word-image-78-300x104.png 300w, /wp-content/uploads/2018/06/word-image-78-768x266.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></p>
<p>注：文件名后缀不要加html</p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="136" height="66" class="wp-image-7471" src="/wp-content/uploads/2018/06/word-image-79.png" /></p>
<h1>十一、搭建后台首页</h1>
<p>第一步：在后台Admin建立一个Index的控制器，输出模板内容</p>
<p><img loading="lazy" decoding="async" width="885" height="275" class="wp-image-7472" src="/wp-content/uploads/2018/06/word-image-80.png" srcset="/wp-content/uploads/2018/06/word-image-80.png 885w, /wp-content/uploads/2018/06/word-image-80-300x93.png 300w, /wp-content/uploads/2018/06/word-image-80-768x239.png 768w" sizes="(max-width: 885px) 100vw, 885px" /></p>
<p>第二步：把我们的后台模板index.html复制到/admin/view/index/目录下面</p>
<p><img loading="lazy" decoding="async" width="1028" height="383" class="wp-image-7473" src="/wp-content/uploads/2018/06/word-image-81.png" srcset="/wp-content/uploads/2018/06/word-image-81.png 1028w, /wp-content/uploads/2018/06/word-image-81-300x112.png 300w, /wp-content/uploads/2018/06/word-image-81-768x286.png 768w, /wp-content/uploads/2018/06/word-image-81-1024x382.png 1024w" sizes="(max-width: 1028px) 100vw, 1028px" /></p>
<p>第三步：把后台模板的left.html 、 top.html 、main.html复复制到/admin/view/index/目录下面.</p>
<p><img loading="lazy" decoding="async" width="744" height="472" class="wp-image-7474" src="/wp-content/uploads/2018/06/word-image-82.png" srcset="/wp-content/uploads/2018/06/word-image-82.png 744w, /wp-content/uploads/2018/06/word-image-82-300x190.png 300w" sizes="(max-width: 744px) 100vw, 744px" /></p>
<p>第四步：在建立left、top、main三个方法</p>
<p><img loading="lazy" decoding="async" width="835" height="533" class="wp-image-7475" src="/wp-content/uploads/2018/06/word-image-83.png" srcset="/wp-content/uploads/2018/06/word-image-83.png 835w, /wp-content/uploads/2018/06/word-image-83-300x191.png 300w, /wp-content/uploads/2018/06/word-image-83-768x490.png 768w" sizes="(max-width: 835px) 100vw, 835px" /></p>
<p>第五步：设置index.html模板的iframe的src路径：</p>
<p><img loading="lazy" decoding="async" width="1238" height="324" class="wp-image-7476" src="/wp-content/uploads/2018/06/word-image-84.png" srcset="/wp-content/uploads/2018/06/word-image-84.png 1238w, /wp-content/uploads/2018/06/word-image-84-300x79.png 300w, /wp-content/uploads/2018/06/word-image-84-768x201.png 768w, /wp-content/uploads/2018/06/word-image-84-1024x268.png 1024w" sizes="(max-width: 1238px) 100vw, 1238px" /></p>
<p>注：助手函数：url(‘模块/控制器/方法’) 生成url地址，在模板中使用函数需要在一对花括号{}前面加个冒号：</p>
<p>第六步：把后台资源（img、css、js）,复制到网站根目录public/admin/目录下面</p>
<p><img loading="lazy" decoding="async" width="1062" height="209" class="wp-image-7477" src="/wp-content/uploads/2018/06/word-image-85.png" srcset="/wp-content/uploads/2018/06/word-image-85.png 1062w, /wp-content/uploads/2018/06/word-image-85-300x59.png 300w, /wp-content/uploads/2018/06/word-image-85-768x151.png 768w, /wp-content/uploads/2018/06/word-image-85-1024x202.png 1024w" sizes="(max-width: 1062px) 100vw, 1062px" /></p>
<p>同时config.php配置文件中，定义一个后台资源目录的路径，在模板中进行统一替换：</p>
<p><img loading="lazy" decoding="async" width="860" height="300" class="wp-image-7478" src="/wp-content/uploads/2018/06/word-image-86.png" srcset="/wp-content/uploads/2018/06/word-image-86.png 860w, /wp-content/uploads/2018/06/word-image-86-300x105.png 300w, /wp-content/uploads/2018/06/word-image-86-768x268.png 768w" sizes="(max-width: 860px) 100vw, 860px" /></p>
<p>第七步：模板中替换使用config函数获取配置进行替换：</p>
<p><img loading="lazy" decoding="async" width="1358" height="710" class="wp-image-7479" src="/wp-content/uploads/2018/06/word-image-87.png" srcset="/wp-content/uploads/2018/06/word-image-87.png 1358w, /wp-content/uploads/2018/06/word-image-87-300x157.png 300w, /wp-content/uploads/2018/06/word-image-87-768x402.png 768w, /wp-content/uploads/2018/06/word-image-87-1024x535.png 1024w" sizes="(max-width: 1358px) 100vw, 1358px" /></p>
<p>和上面操作一样分别替换top.html、left.html、main.html的静态资源目录。</p>
<p>最终效果：</p>
<p><img loading="lazy" decoding="async" width="761" height="479" class="wp-image-7480" src="/wp-content/uploads/2018/06/word-image-88.png" srcset="/wp-content/uploads/2018/06/word-image-88.png 761w, /wp-content/uploads/2018/06/word-image-88-300x189.png 300w" sizes="(max-width: 761px) 100vw, 761px" /></p>
<p>注：助手函数config(‘配置名’)，是获取配置文件中的值。模板中使用需要在{}前面加个冒号：。</p>
<p>助手函数手册位置：附录&#8211;》助手函数</p>
<h1>十二、搭建登录页</h1>
<p>第一步：在后台admin建立一个Public控制器，并建立一个login的方法，输出模板内容</p>
<p><img loading="lazy" decoding="async" width="815" height="262" class="wp-image-7482" src="/wp-content/uploads/2018/06/word-image-89.png" srcset="/wp-content/uploads/2018/06/word-image-89.png 815w, /wp-content/uploads/2018/06/word-image-89-300x96.png 300w, /wp-content/uploads/2018/06/word-image-89-768x247.png 768w" sizes="(max-width: 815px) 100vw, 815px" /></p>
<p>第二步：把后台模板login.html赋值到/admin/view/public/目录下面，并替换静态资源文件路径</p>
<p><img loading="lazy" decoding="async" width="1221" height="368" class="wp-image-7483" src="/wp-content/uploads/2018/06/word-image-90.png" srcset="/wp-content/uploads/2018/06/word-image-90.png 1221w, /wp-content/uploads/2018/06/word-image-90-300x90.png 300w, /wp-content/uploads/2018/06/word-image-90-768x231.png 768w, /wp-content/uploads/2018/06/word-image-90-1024x309.png 1024w" sizes="(max-width: 1221px) 100vw, 1221px" /></p>
<p>效果：<br />
<img loading="lazy" decoding="async" width="775" height="341" class="wp-image-7484" src="/wp-content/uploads/2018/06/word-image-91.png" srcset="/wp-content/uploads/2018/06/word-image-91.png 775w, /wp-content/uploads/2018/06/word-image-91-300x132.png 300w, /wp-content/uploads/2018/06/word-image-91-768x338.png 768w" sizes="(max-width: 775px) 100vw, 775px" /></p>
<p>sublime快捷键：</p>
<p>替换：ctrl+h</p>
<p>找文件：ctrl+p</p>
<h1>十三、控制器中的页面跳转和重定向</h1>
<h2>1、跳转</h2>
<p>在应用开发中，经常会遇到一些带有提示信息的跳转页面，例如操作成功或者操作错误页面，并且自动跳转到另外一个目标页面。系统的\think\Controller类内置了两个跳转方法success和error，用于页面跳转提示</p>
<p>成功跳转：$this-&gt;success($msg,$url,$data,$time)</p>
<p>失败跳转：$this-&gt;error($msg,$url,$data,$time))</p>
<p>参数说明：</p>
<ul>
<li>msg:跳转的提示信息</li>
<li>url:跳转的地址。 建议用助手函数url()生成地址。，失败默认跳回上一页。一般不需要指定</li>
<li>data: 返回的数据，没有则留空</li>
<li>time:默认成功和失败都是3秒，</li>
</ul>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="786" height="379" class="wp-image-7485" src="/wp-content/uploads/2018/06/word-image-92.png" srcset="/wp-content/uploads/2018/06/word-image-92.png 786w, /wp-content/uploads/2018/06/word-image-92-300x145.png 300w, /wp-content/uploads/2018/06/word-image-92-768x370.png 768w" sizes="(max-width: 786px) 100vw, 786px" /></p>
<p>success和error方法源码位置： <img loading="lazy" decoding="async" width="392" height="26" class="wp-image-7486" src="/wp-content/uploads/2018/06/word-image-93.png" srcset="/wp-content/uploads/2018/06/word-image-93.png 392w, /wp-content/uploads/2018/06/word-image-93-300x20.png 300w" sizes="(max-width: 392px) 100vw, 392px" /></p>
<h2>重定向</h2>
<p>语法:</p>
<p>$this-&gt; redirect(url,[$params])</p>
<p>参数说明：</p>
<p>第一个参数必填，后面两个个参数可缺省。</p>
<ul>
<li>$url：跳转的地址, 形式为 “模块/控制器/方法&#8221; 。</li>
</ul>
<p>若直接写方法名如：$this-&gt; redirect(‘index’)，默认会重定向到当前模块的当前控制器的index方法。</p>
<p>若直接写控制器名和方法名如：$this-&gt; redirect(‘index/index’)，默认会重定向到当前模块的index控制器的index方法。</p>
<ul>
<li>$params：跳转携带的参数，数组形式如：传id等于3，array(“id”=&gt;3)</li>
</ul>
<p>$this -&gt; redirect(分组/控制器/操作方法)</p>
<p>跳转到的地址：http://网址/分组/控制器/操作方法</p>
<p>$this -&gt; redirect(分组/控制器/操作方法,[参数1=&gt;值1,参数2=&gt;值2])</p>
<p>跳转到的地址：<a href="/goto/8icy" rel="nofollow">http://网址/分组/控制器/操作方法/参数1/值1/参数2/值</a>2</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="800" height="196" class="wp-image-7487" src="/wp-content/uploads/2018/06/word-image-94.png" srcset="/wp-content/uploads/2018/06/word-image-94.png 800w, /wp-content/uploads/2018/06/word-image-94-300x74.png 300w, /wp-content/uploads/2018/06/word-image-94-768x188.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<p>问：什么时候使用跳转和重定向？</p>
<p>答：</p>
<p>1、需要给用户操作的提示信息，则用跳转。</p>
<p>一般是删除或编辑失败的时候，这需要给用户提示错误信息，操作失败则用跳转error，成功用success。</p>
<p>2、不需要给任何提示信息，则用重定向。</p>
<p>如用户登录成功不需要给提示信息则直接redirect重定向到首页，登录失败就用error给用户提示错误信息。</p>
<h1>请求Request</h1>
<p>手册参考位置：请求&#8211;&gt;请求信息</p>
<h2>获取Request对象</h2>
<p>图解Request对象、response对象：</p>
<p><img loading="lazy" decoding="async" width="744" height="109" class="wp-image-7488" src="/wp-content/uploads/2018/06/word-image-95.png" srcset="/wp-content/uploads/2018/06/word-image-95.png 744w, /wp-content/uploads/2018/06/word-image-95-300x44.png 300w" sizes="(max-width: 744px) 100vw, 744px" /></p>
<p>图解说明：</p>
<ul>
<li>服务端server把客户端请求过来的相关信息都封装在一个Request对象中。如请求地址、请求参数、请求类型、上传的文件信息等。</li>
<li>服务端server把响应给浏览器的相关信息都封装在一个Response对象。如响应http状态码200给客户端等。</li>
</ul>
<p>获取Request对象的方式：</p>
<p>方式一：</p>
<p>引用\think\Request类 ，$request = Request::instance();</p>
<p><img loading="lazy" decoding="async" width="673" height="350" class="wp-image-7489" src="/wp-content/uploads/2018/06/word-image-96.png" srcset="/wp-content/uploads/2018/06/word-image-96.png 673w, /wp-content/uploads/2018/06/word-image-96-300x156.png 300w" sizes="(max-width: 673px) 100vw, 673px" /></p>
<p>助手调试函数dump()；内部封装pre格式化标签。</p>
<p>方式二（最简单的方式）：</p>
<p>通过tp5框架提供的助手函数request()</p>
<p>$request = request();</p>
<p><img loading="lazy" decoding="async" width="698" height="240" class="wp-image-7490" src="/wp-content/uploads/2018/06/word-image-97.png" srcset="/wp-content/uploads/2018/06/word-image-97.png 698w, /wp-content/uploads/2018/06/word-image-97-300x103.png 300w" sizes="(max-width: 698px) 100vw, 698px" /></p>
<p>方式三：</p>
<p>通过依赖注入（闭包）的方式，把Request对象注入到方法内部</p>
<p>public function 方法名(Request $request){}</p>
<p><img loading="lazy" decoding="async" width="640" height="349" class="wp-image-7491" src="/wp-content/uploads/2018/06/word-image-98.png" srcset="/wp-content/uploads/2018/06/word-image-98.png 640w, /wp-content/uploads/2018/06/word-image-98-300x164.png 300w" sizes="(max-width: 640px) 100vw, 640px" /></p>
<p>相当于把Request类的对象$request作为p4的参数。</p>
<h2>2、获取请求信息</h2>
<p>手册参考位置：请求&#8211;&gt;请求信息</p>
<p>$request-&gt;domain(); // 获取当前域名</p>
<p>$request-&gt;baseFile(); // 获取当前入口文件,不含域名</p>
<p>$request-&gt;url(); // 获取当前URL地址</p>
<p>$request-&gt;url(true); // 包含域名的完整URL地址</p>
<p>$request-&gt;baseUrl(); // 获取当前URL地址 不含QUERY_STRING</p>
<p>$request-&gt;pathinfo(); // 获取URL地址中的PATH_INFO信息</p>
<p>$request-&gt;path(); // 获取URL地址中的PATH_INFO信息 不含后缀</p>
<p>$request-&gt;ext(); // 获取URL地址中的后缀信息</p>
<p>$request-&gt;header(); // 获取当前请求的HTTP 请求头信息</p>
<p>$request-&gt;module(); // 获取当前模块名称</p>
<p>$request-&gt;controller(); // 获取当前控制器名称</p>
<p>$request-&gt;action(); // 获取当前操作名称</p>
<p>$request-&gt;method(); // 获取请求方法</p>
<p>$request-&gt;type(); // 获取资源类型</p>
<p>$request-&gt;ip(); // 获取访问ip地址</p>
<p>$request-&gt;isAjax(); // 判断 是否是ajax请求</p>
<p>$request-&gt;isPost(); // 判断 是否是post请求</p>
<p>$request-&gt;isGet(); // 判断 是否是get请求</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="967" height="334" class="wp-image-7492" src="/wp-content/uploads/2018/06/word-image-99.png" srcset="/wp-content/uploads/2018/06/word-image-99.png 967w, /wp-content/uploads/2018/06/word-image-99-300x104.png 300w, /wp-content/uploads/2018/06/word-image-99-768x265.png 768w" sizes="(max-width: 967px) 100vw, 967px" /></p>
<h2>3、获取请求参数</h2>
<p>手册参考位置：请求&#8211;&gt;输入变量</p>
<p>语法：变量类型方法(&#8216;变量名/变量修饰符&#8217;,&#8217;默认值&#8217;,&#8217;过滤方法&#8217;)</p>
<table>
<thead>
<tr>
<th><strong>方法</strong></th>
<th><strong>描述</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>param</td>
<td>获取当前请求的变量信息</td>
</tr>
<tr>
<td>get</td>
<td>获取 $_GET 变量</td>
</tr>
<tr>
<td>post</td>
<td>获取 $_POST 变量</td>
</tr>
<tr>
<td>session</td>
<td>获取 $_SESSION 变量</td>
</tr>
<tr>
<td>cookie</td>
<td>获取 $_COOKIE 变量</td>
</tr>
<tr>
<td>request</td>
<td>获取 $_REQUEST 变量</td>
</tr>
<tr>
<td>server</td>
<td>获取 $_SERVER 变量</td>
</tr>
<tr>
<td>env</td>
<td>获取 $_ENV 变量</td>
</tr>
<tr>
<td>route</td>
<td>获取 路由（包括PATHINFO） 变量</td>
</tr>
<tr>
<td>file</td>
<td>获取 $_FILES 变量</td>
</tr>
</tbody>
</table>
<h3>（1）获取PARAM变量</h3>
<p>PARAM变量是框架提供的用于自动识别GET、POST或者的一种变量获取方式，是系统推荐的获取请求参数的方法，用法如下：</p>
<p>// 获取当前请求的name变量</p>
<p>$request-&gt;param(&#8216;name&#8217;);</p>
<p>// 获取当前请求的所有变量（经过过滤）</p>
<p>$request-&gt;param();</p>
<p>// 获取当前请求的所有变量（原始数据）</p>
<p>$request-&gt;param(false);</p>
<p>// 获取当前请求的所有变量（包含上传文件）</p>
<p>$request-&gt;param(true);</p>
<p>注：param方法会把当前请求类型的参数和PATH_INFO变量以及GET请求合并。</p>
<p>或使用助手函数实现：</p>
<p>input(&#8216;param.name&#8217;);</p>
<p>input(&#8216;param.&#8217;);</p>
<p>或者</p>
<p>input(&#8216;name&#8217;);</p>
<p>input(&#8221;);</p>
<p>因为input函数默认底默认就采用PARAM方式进行读取变量。</p>
<h3>（2）获取GET变量</h3>
<p>使用内置的助手函数input获取get参数</p>
<p>input(&#8216;id&#8217;);</p>
<p>input(&#8216;name&#8217;);</p>
<p>input(&#8216;get.&#8217;); //获取整个get数组参数</p>
<p>代码如下：</p>
<ol>
<li>把表单设置get方式提交，不写action默认跳转到当前地址</li>
</ol>
<p><img loading="lazy" decoding="async" width="844" height="299" class="wp-image-7493" src="/wp-content/uploads/2018/06/word-image-100.png" srcset="/wp-content/uploads/2018/06/word-image-100.png 844w, /wp-content/uploads/2018/06/word-image-100-300x106.png 300w, /wp-content/uploads/2018/06/word-image-100-768x272.png 768w" sizes="(max-width: 844px) 100vw, 844px" /></p>
<p>假设输入的数据如下：</p>
<p><img loading="lazy" decoding="async" width="492" height="230" class="wp-image-7494" src="/wp-content/uploads/2018/06/word-image-101.png" srcset="/wp-content/uploads/2018/06/word-image-101.png 492w, /wp-content/uploads/2018/06/word-image-101-300x140.png 300w" sizes="(max-width: 492px) 100vw, 492px" /></p>
<p>b、在当前方法p3中接收整个get参数和单个get参数，结果</p>
<p><img loading="lazy" decoding="async" width="1047" height="260" class="wp-image-7495" src="/wp-content/uploads/2018/06/word-image-102.png" srcset="/wp-content/uploads/2018/06/word-image-102.png 1047w, /wp-content/uploads/2018/06/word-image-102-300x74.png 300w, /wp-content/uploads/2018/06/word-image-102-768x191.png 768w, /wp-content/uploads/2018/06/word-image-102-1024x254.png 1024w" sizes="(max-width: 1047px) 100vw, 1047px" /></p>
<h3>（3）获取POST变量</h3>
<p>使用助手函数实现：</p>
<p>input(&#8216;name&#8217;);</p>
<p>input(&#8216;post.&#8217;); //获取整个post数组参数</p>
<p>代码如下：</p>
<p>a、把表单设置post方式提交，不写action默认跳转到当前地址</p>
<p><img loading="lazy" decoding="async" width="756" height="285" class="wp-image-7496" src="/wp-content/uploads/2018/06/word-image-103.png" srcset="/wp-content/uploads/2018/06/word-image-103.png 756w, /wp-content/uploads/2018/06/word-image-103-300x113.png 300w" sizes="(max-width: 756px) 100vw, 756px" /></p>
<p>假设输入的数据如下：</p>
<p><img loading="lazy" decoding="async" width="426" height="126" class="wp-image-7497" src="/wp-content/uploads/2018/06/word-image-104.png" srcset="/wp-content/uploads/2018/06/word-image-104.png 426w, /wp-content/uploads/2018/06/word-image-104-300x89.png 300w" sizes="(max-width: 426px) 100vw, 426px" /></p>
<p>b、在当前方法p3中判断是否是post请求，获取整个post参数和单个post参数</p>
<p><img loading="lazy" decoding="async" width="939" height="355" class="wp-image-7498" src="/wp-content/uploads/2018/06/word-image-105.png" srcset="/wp-content/uploads/2018/06/word-image-105.png 939w, /wp-content/uploads/2018/06/word-image-105-300x113.png 300w, /wp-content/uploads/2018/06/word-image-105-768x290.png 768w" sizes="(max-width: 939px) 100vw, 939px" /></p>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7391.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5.0（二）数据库操作、模型 CURD 操作、常用函数、时间戳自动维护、DB 构造器操作数据库、后台登录、后台退出、登录防翻墙、登录验证</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7499.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7499.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:43:29 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[DB 构造器操作数据库]]></category>
		<category><![CDATA[后台登录]]></category>
		<category><![CDATA[后台退出]]></category>
		<category><![CDATA[常用函数]]></category>
		<category><![CDATA[数据库操作]]></category>
		<category><![CDATA[时间戳自动维护]]></category>
		<category><![CDATA[模型 CURD 操作]]></category>
		<category><![CDATA[登录防翻墙]]></category>
		<category><![CDATA[登录验证]]></category>
		<guid isPermaLink="false">/?p=7499</guid>

					<description><![CDATA[TP5第二天 十五、数据库操作 在TP5操作数据库常用有两种方式： 通过Db构造器 如：Db::table(&#038; [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>TP5第二天</h1>
<h1>十五、数据库操作</h1>
<p>在TP5操作数据库常用有两种方式：</p>
<ul>
<li>通过Db构造器</li>
</ul>
<p>如：Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;status&#8217;,1)-&gt;select(); // #带数据表前缀</p>
<p>如：Db::name(&#8216;user&#8217;)-&gt;where(&#8216;status&#8217;,1)-&gt;select(); #不带表前缀</p>
<ul>
<li>通过模型类</li>
</ul>
<p>如：取出主键为1的数据</p>
<p>$user = User::get(1);</p>
<p>首先配置数据库的连接信息</p>
<h2>创建数据库数据表，配置数据库信息</h2>
<p>在application/database.php文件中添加下面的配置参数：</p>
<p><img loading="lazy" decoding="async" width="871" height="556" class="wp-image-7500" src="/wp-content/uploads/2018/06/word-image-106.png" srcset="/wp-content/uploads/2018/06/word-image-106.png 871w, /wp-content/uploads/2018/06/word-image-106-300x192.png 300w, /wp-content/uploads/2018/06/word-image-106-768x490.png 768w" sizes="(max-width: 871px) 100vw, 871px" /></p>
<p>同时创建好数据库和数据表：</p>
<ol>
<li>创建数据库article:</li>
</ol>
<p>create database article;</p>
<p>2、创建数据表tp_user(用户表)、tp_category（分类表）、tp_article（文章表）</p>
<p>tp_user表结构：</p>
<p>create table tp_user(</p>
<p>user_id int not null auto_increment,</p>
<p>username varchar(30) not null default &#8221; comment &#8216;用户名&#8217;,</p>
<p>password char(32) not null default &#8221; comment &#8216;密码&#8217;,</p>
<p>primary key(user_id)</p>
<p>)engine = Innodb default charset = utf8;</p>
<p>tp_category表结构：</p>
<p>create table tp_category(</p>
<p>cat_id smallint not null auto_increment,</p>
<p>cat_name varchar(30) not null default &#8221; comment &#8216;分类名称&#8217;,</p>
<p>pid smallint not null default 0 comment &#8216;父分类的id&#8217;,</p>
<p>create_time int not null default 0 comment &#8216;创建时间&#8217;,</p>
<p>update_time int not null default 0 comment &#8216;更新时间&#8217;,</p>
<p>primary key(cat_id)</p>
<p>)engine = Innodb default charset = utf8;</p>
<p>tp_article表结构：</p>
<p>create table tp_article(</p>
<p>article_id smallint not null auto_increment,</p>
<p>title varchar(30) not null default &#8221; comment &#8216;文章标题&#8217;,</p>
<p>content text comment &#8216;文章内容&#8217;,</p>
<p>cat_id smallint not null default 0 comment &#8216;文章所属分类&#8217;,</p>
<p>ori_img varchar(150) not null default &#8221; comment &#8216;原图的路径&#8217;,</p>
<p>thumb_img varchar(150) not null default &#8221; comment &#8216;缩略图的路径&#8217;,</p>
<p>create_time int not null default 0 comment &#8216;创建时间&#8217;,</p>
<p>update_time int not null default 0 comment &#8216;更新时间&#8217;,</p>
<p>primary key(article_id)</p>
<p>)engine = Innodb default charset = utf8;</p>
<p>注：表名加前缀tp_,用于区分多个项目。</p>
<ol>
<li>测试数据库是否连接成功，可以向表添加几条数据，进行查询</li>
</ol>
<p><img loading="lazy" decoding="async" width="444" height="79" class="wp-image-7501" src="/wp-content/uploads/2018/06/word-image-107.png" srcset="/wp-content/uploads/2018/06/word-image-107.png 444w, /wp-content/uploads/2018/06/word-image-107-300x53.png 300w" sizes="(max-width: 444px) 100vw, 444px" /></p>
<p><img loading="lazy" decoding="async" width="772" height="250" class="wp-image-7502" src="/wp-content/uploads/2018/06/word-image-108.png" srcset="/wp-content/uploads/2018/06/word-image-108.png 772w, /wp-content/uploads/2018/06/word-image-108-300x97.png 300w, /wp-content/uploads/2018/06/word-image-108-768x249.png 768w" sizes="(max-width: 772px) 100vw, 772px" /></p>
<p>结果：</p>
<p><img loading="lazy" decoding="async" width="266" height="239" class="wp-image-7503" src="/wp-content/uploads/2018/06/word-image-109.png" /></p>
<p>说明连接成功。</p>
<h2>模型</h2>
<h3>模型认识</h3>
<p>M:Model模型</p>
<p>作用：主要对数据库进行一些增删改查的操作。</p>
<h3>模型的定义</h3>
<p>一般而言，一个表对应一个模型，如果只是对表进行最基本的增删改查，不建模型也是可以操作表数据的，但是如果数据逻辑比较复杂，我们可以把这些数据逻辑定义在模型中，为了和业务逻辑分开，代码结构也比较清晰，也方便后期维护。</p>
<p>个人建议最好的做法就是以下两点：</p>
<p>①业务逻辑写在控制器中</p>
<p>②数据逻辑写在模型中</p>
<p>如有一个文章分类表，名为tp_category，此表对应的模型类名和模型文件定义如下：</p>
<p>模型类名： Category 注：驼峰法，除开表前缀的数据表名称。</p>
<p>模型类文件：Category.php 表名+.php</p>
<p>模型类文件所在位置：模块名/model/Category.php</p>
<p>给表tp_category建立模型文件如下：</p>
<p><img loading="lazy" decoding="async" width="692" height="218" class="wp-image-7504" src="/wp-content/uploads/2018/06/word-image-110.png" srcset="/wp-content/uploads/2018/06/word-image-110.png 692w, /wp-content/uploads/2018/06/word-image-110-300x95.png 300w" sizes="(max-width: 692px) 100vw, 692px" /></p>
<p>其中模型中定义的属性pk为表的主键名称，若不指定则框架会自动识别。</p>
<p>有关表名的注意事项：</p>
<p>手册位置： 模型-&gt;定义</p>
<p><img loading="lazy" decoding="async" width="914" height="461" class="wp-image-7505" src="/wp-content/uploads/2018/06/word-image-111.png" srcset="/wp-content/uploads/2018/06/word-image-111.png 914w, /wp-content/uploads/2018/06/word-image-111-300x151.png 300w, /wp-content/uploads/2018/06/word-image-111-768x387.png 768w" sizes="(max-width: 914px) 100vw, 914px" /></p>
<h3>（3）实例化模型</h3>
<p>方式一：在控制器中实例化模型首先引入其模型类所在的命名空间，如引入上面的Category</p>
<p>模型：</p>
<p>use app\admin\model\Category;</p>
<p>然后实例化模型：</p>
<p>// 静态调用</p>
<p>$data = Category::get(1); //获取主键值为1的数据</p>
<p>// 实例化模型</p>
<p>$cate= new Category();</p>
<p>$data = $cate-&gt;get(1);</p>
<p><img loading="lazy" decoding="async" width="503" height="239" class="wp-image-7506" src="/wp-content/uploads/2018/06/word-image-112.png" srcset="/wp-content/uploads/2018/06/word-image-112.png 503w, /wp-content/uploads/2018/06/word-image-112-300x143.png 300w" sizes="(max-width: 503px) 100vw, 503px" /></p>
<p>其中打印$dataObj是一个当前数据的对象：</p>
<p><img loading="lazy" decoding="async" width="479" height="584" class="wp-image-7507" src="/wp-content/uploads/2018/06/word-image-113.png" srcset="/wp-content/uploads/2018/06/word-image-113.png 479w, /wp-content/uploads/2018/06/word-image-113-246x300.png 246w" sizes="(max-width: 479px) 100vw, 479px" /></p>
<p>或者：</p>
<p><img loading="lazy" decoding="async" width="594" height="260" class="wp-image-7508" src="/wp-content/uploads/2018/06/word-image-114.png" srcset="/wp-content/uploads/2018/06/word-image-114.png 594w, /wp-content/uploads/2018/06/word-image-114-300x131.png 300w" sizes="(max-width: 594px) 100vw, 594px" /></p>
<p>方式二：或者直接可以使用助手函数model：</p>
<p>$cate = model(&#8216;Category&#8217;);</p>
<p>$data = $cate-&gt;get(1);</p>
<p><img loading="lazy" decoding="async" width="852" height="331" class="wp-image-7509" src="/wp-content/uploads/2018/06/word-image-115.png" srcset="/wp-content/uploads/2018/06/word-image-115.png 852w, /wp-content/uploads/2018/06/word-image-115-300x117.png 300w, /wp-content/uploads/2018/06/word-image-115-768x298.png 768w" sizes="(max-width: 852px) 100vw, 852px" /></p>
<h1>十六、模型CURD操作</h1>
<p>C-create：新增数据</p>
<p>U-update：更新数据</p>
<p>R-read：查询数据</p>
<p>D-delete：删除数据</p>
<h2>新增数据</h2>
<p>手册位置：模型-&gt;新增</p>
<h3>（1）添加一条数据</h3>
<p>$model-&gt;save($data);</p>
<p>参数：$data为一维数组，其中[‘字段名’=&gt;’数据’]</p>
<p>返回：成功返回写入的记录数</p>
<p><img loading="lazy" decoding="async" width="678" height="198" class="wp-image-7510" src="/wp-content/uploads/2018/06/word-image-116.png" srcset="/wp-content/uploads/2018/06/word-image-116.png 678w, /wp-content/uploads/2018/06/word-image-116-300x88.png 300w" sizes="(max-width: 678px) 100vw, 678px" /></p>
<h3>获取自增后的主键值</h3>
<p>$model-&gt;save($data);</p>
<p>echo $model-&gt;主键字段名;</p>
<p><img loading="lazy" decoding="async" width="598" height="240" class="wp-image-7511" src="/wp-content/uploads/2018/06/word-image-117.png" srcset="/wp-content/uploads/2018/06/word-image-117.png 598w, /wp-content/uploads/2018/06/word-image-117-300x120.png 300w" sizes="(max-width: 598px) 100vw, 598px" /></p>
<p>数据表数据如下：</p>
<p><img loading="lazy" decoding="async" width="541" height="64" class="wp-image-7512" src="/wp-content/uploads/2018/06/word-image-118.png" srcset="/wp-content/uploads/2018/06/word-image-118.png 541w, /wp-content/uploads/2018/06/word-image-118-300x35.png 300w" sizes="(max-width: 541px) 100vw, 541px" /></p>
<h3>（3）过滤非数据表字段</h3>
<ul>
<li>只允许数据表的字段写入</li>
</ul>
<p>$model-&gt;allowField(true)-&gt;save($data) ;</p>
<ul>
<li>只允许name和email字段写入</li>
</ul>
<p>$model-&gt;allowField([‘name’,’email’])-&gt;save($data) ;</p>
<p>代码：</p>
<p><img loading="lazy" decoding="async" width="609" height="138" class="wp-image-7513" src="/wp-content/uploads/2018/06/word-image-119.png" srcset="/wp-content/uploads/2018/06/word-image-119.png 609w, /wp-content/uploads/2018/06/word-image-119-300x68.png 300w" sizes="(max-width: 609px) 100vw, 609px" /></p>
<h3>（4）添加多条数据</h3>
<ul>
<li>$model-&gt;saveAll();</li>
</ul>
<p><img loading="lazy" decoding="async" width="665" height="272" class="wp-image-7514" src="/wp-content/uploads/2018/06/word-image-120.png" srcset="/wp-content/uploads/2018/06/word-image-120.png 665w, /wp-content/uploads/2018/06/word-image-120-300x123.png 300w" sizes="(max-width: 665px) 100vw, 665px" /></p>
<p>成功：返回数组对象集合。</p>
<p><img loading="lazy" decoding="async" width="461" height="207" class="wp-image-7515" src="/wp-content/uploads/2018/06/word-image-121.png" srcset="/wp-content/uploads/2018/06/word-image-121.png 461w, /wp-content/uploads/2018/06/word-image-121-300x135.png 300w" sizes="(max-width: 461px) 100vw, 461px" /></p>
<p>注：其中每条数据都是作为当前模型类的对象。</p>
<p>数据表如下：<br />
<img loading="lazy" decoding="async" width="494" height="55" class="wp-image-7516" src="/wp-content/uploads/2018/06/word-image-122.png" srcset="/wp-content/uploads/2018/06/word-image-122.png 494w, /wp-content/uploads/2018/06/word-image-122-300x33.png 300w" sizes="(max-width: 494px) 100vw, 494px" /></p>
<h2>更新数据-U</h2>
<p>手册位置：模型&#8211;&gt;更新</p>
<h3>更新方式一</h3>
<ul>
<li>$model-&gt;save($data,更新条件)</li>
<li>$model-&gt;isUpdate(true)-&gt;save($data)</li>
</ul>
<p>可以通过isUpdate方法指定save为执行更新操作，其中$data中必须带更新的主键值</p>
<ul>
<li>若需要过滤非数据表的字段数据，使用：</li>
</ul>
<p>$model-&gt;-&gt;isUpdate(true)-&gt;allowField(true)-&gt;save($data)</p>
<p><img loading="lazy" decoding="async" width="633" height="300" class="wp-image-7517" src="/wp-content/uploads/2018/06/word-image-123.png" srcset="/wp-content/uploads/2018/06/word-image-123.png 633w, /wp-content/uploads/2018/06/word-image-123-300x142.png 300w" sizes="(max-width: 633px) 100vw, 633px" /></p>
<p><img loading="lazy" decoding="async" width="651" height="64" class="wp-image-7518" src="/wp-content/uploads/2018/06/word-image-124.png" srcset="/wp-content/uploads/2018/06/word-image-124.png 651w, /wp-content/uploads/2018/06/word-image-124-300x29.png 300w" sizes="(max-width: 651px) 100vw, 651px" /></p>
<h3>（2）更新方式二</h3>
<ul>
<li>$model-&gt;update($data)</li>
</ul>
<p>参数$data为一维数组，键名为表字段名，其中更新必须指定更新条件，否则更新失败。</p>
<p>成功返回当前数据对象。</p>
<p><img loading="lazy" decoding="async" width="571" height="193" class="wp-image-7519" src="/wp-content/uploads/2018/06/word-image-125.png" srcset="/wp-content/uploads/2018/06/word-image-125.png 571w, /wp-content/uploads/2018/06/word-image-125-300x101.png 300w" sizes="(max-width: 571px) 100vw, 571px" /></p>
<p><img loading="lazy" decoding="async" width="471" height="26" class="wp-image-7520" src="/wp-content/uploads/2018/06/word-image-126.png" srcset="/wp-content/uploads/2018/06/word-image-126.png 471w, /wp-content/uploads/2018/06/word-image-126-300x17.png 300w" sizes="(max-width: 471px) 100vw, 471px" /></p>
<h2>删除数据-D</h2>
<h3>（1）调用静态方法删除一条数据</h3>
<p>模型类名::destroy(1); 如：User::destroy(1) 删除主键为1的记录</p>
<h3>（2）调用静态方法批量删除多个数据</h3>
<p>模型类名::destroy(‘1,2,3’); 删除主键为1,2,3的记录</p>
<p>或</p>
<p>模型类名::destroy([1,2,3]);</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="627" height="170" class="wp-image-7521" src="/wp-content/uploads/2018/06/word-image-127.png" srcset="/wp-content/uploads/2018/06/word-image-127.png 627w, /wp-content/uploads/2018/06/word-image-127-300x81.png 300w" sizes="(max-width: 627px) 100vw, 627px" /></p>
<h2>查询数据-R</h2>
<h3>（1）根据主键值获取记录一条记录</h3>
<p>$dataObj = 模型类名::get(主键值)</p>
<p>$dataObj = 模型类名::find(主键值)</p>
<p>成功返回当前数据的对象。</p>
<p><img loading="lazy" decoding="async" width="647" height="140" class="wp-image-7522" src="/wp-content/uploads/2018/06/word-image-128.png" srcset="/wp-content/uploads/2018/06/word-image-128.png 647w, /wp-content/uploads/2018/06/word-image-128-300x65.png 300w" sizes="(max-width: 647px) 100vw, 647px" /></p>
<h3>（2）根据主键值获取多条记录</h3>
<p>$dataObj= 模型类名::all(‘1,2,3’); //获取主键值为1,2,3的记录</p>
<p>或</p>
<p>$dataObj= 模型类名::all([1,2,3]); //获取主键值为1,2,3的记录</p>
<p>$dataObj= 模型类名::select(); //获取表中的所有数据</p>
<p>或</p>
<p>$dataObj= 模型类名::all();</p>
<p>all和select都是返回当前查询数组的数据对象集合。</p>
<p><img loading="lazy" decoding="async" width="596" height="223" class="wp-image-7523" src="/wp-content/uploads/2018/06/word-image-129.png" srcset="/wp-content/uploads/2018/06/word-image-129.png 596w, /wp-content/uploads/2018/06/word-image-129-300x112.png 300w" sizes="(max-width: 596px) 100vw, 596px" /></p>
<h2>连贯操作</h2>
<p>手册位置：数据库&#8211;&gt;查询构造器&#8211;&gt;链式操作</p>
<p>注： 模型的链式操作方法和Db构造器链式操作的方法都通用；</p>
<p>TP5常用的模型连贯操作方法如下：</p>
<p>方法说明：</p>
<ul>
<li>field(“field1,field2&#8230;”)：查询指定的字段field1和field2,多个用逗号隔开</li>
<li>alias(‘数据表别名’)：给当前数据表设置别名,join联表时用的多</li>
<li>where(查询条件)：查询条件可以为表达式查询、数组查询、字符串查询。</li>
<li>order(“field desc”)：把查询的到结果集进行字段field降序（desc）或升序(asc)。</li>
<li>group(“field”): 把查询的到结果集进行字段field分组。</li>
<li>limit(offset,length): 获取结果集指定条数的数据， offset为起始位置，length为获取记录的条数。</li>
<li>join()：与其他表进行关联查询</li>
</ul>
<p>注意：</p>
<p>以上的连贯操作方法都是返回当前模型的对象，即方法底层都是返回当前模型对象即return $this,所以他们之间的调用顺序不用按照原生的sql顺序来调用，但如果是查询数据，查询语句的最末端一定要确保是select或者是find方法。</p>
<p>在原生的sql语句中一定要按照先后顺序调用：</p>
<p>原生sql语句执行的先后顺序： join==&gt;where ==&gt; group ==&gt; having==&gt;order==&gt;limit</p>
<p>在tp5中以上的连贯操作都不需要按照顺序。</p>
<h3>（1）where表达式查询条件</h3>
<p><img loading="lazy" decoding="async" width="712" height="587" class="wp-image-7524" src="/wp-content/uploads/2018/06/word-image-130.png" srcset="/wp-content/uploads/2018/06/word-image-130.png 712w, /wp-content/uploads/2018/06/word-image-130-300x247.png 300w" sizes="(max-width: 712px) 100vw, 712px" /></p>
<p>代码如下：</p>
<p>例1：</p>
<p><img loading="lazy" decoding="async" width="798" height="189" class="wp-image-7525" src="/wp-content/uploads/2018/06/word-image-131.png" srcset="/wp-content/uploads/2018/06/word-image-131.png 798w, /wp-content/uploads/2018/06/word-image-131-300x71.png 300w, /wp-content/uploads/2018/06/word-image-131-768x182.png 768w" sizes="(max-width: 798px) 100vw, 798px" /></p>
<p>获取生成组装的sql语句： buildSql()</p>
<p><img loading="lazy" decoding="async" width="1020" height="344" class="wp-image-7526" src="/wp-content/uploads/2018/06/word-image-132.png" srcset="/wp-content/uploads/2018/06/word-image-132.png 1020w, /wp-content/uploads/2018/06/word-image-132-300x101.png 300w, /wp-content/uploads/2018/06/word-image-132-768x259.png 768w" sizes="(max-width: 1020px) 100vw, 1020px" /></p>
<p>可见，多个where连续调用，默认是and连接符。 如果想使用or,可以使用方法whereOr()</p>
<p><img loading="lazy" decoding="async" width="907" height="234" class="wp-image-7527" src="/wp-content/uploads/2018/06/word-image-133.png" srcset="/wp-content/uploads/2018/06/word-image-133.png 907w, /wp-content/uploads/2018/06/word-image-133-300x77.png 300w, /wp-content/uploads/2018/06/word-image-133-768x198.png 768w" sizes="(max-width: 907px) 100vw, 907px" /></p>
<h3>（2）where数组查询条件</h3>
<p>完整语法：</p>
<p>$where = [</p>
<p>‘字段名1’=&gt; [表达式，‘值’]</p>
<p>‘字段名2’=&gt; [表达式，‘值’]</p>
<p>]</p>
<p>如果是等值（=）查询，可以不用指定表达式，直接写值即可</p>
<p>$where = [</p>
<p>‘字段名’ =&gt; ‘值’</p>
<p>]</p>
<p>//默认多字段查询，是and链接。</p>
<p>例1：</p>
<p><img loading="lazy" decoding="async" width="817" height="159" class="wp-image-7528" src="/wp-content/uploads/2018/06/word-image-134.png" srcset="/wp-content/uploads/2018/06/word-image-134.png 817w, /wp-content/uploads/2018/06/word-image-134-300x58.png 300w, /wp-content/uploads/2018/06/word-image-134-768x149.png 768w" sizes="(max-width: 817px) 100vw, 817px" /></p>
<h3>（3）where字符串查询条件</h3>
<p>where(字符串条件)</p>
<p><img loading="lazy" decoding="async" width="764" height="188" class="wp-image-7529" src="/wp-content/uploads/2018/06/word-image-135.png" srcset="/wp-content/uploads/2018/06/word-image-135.png 764w, /wp-content/uploads/2018/06/word-image-135-300x74.png 300w" sizes="(max-width: 764px) 100vw, 764px" /></p>
<p>注：只能是类名::才可以调用方法，如果是对象调用，需要实例化对象，通过对象-&gt;去调用：</p>
<p><img loading="lazy" decoding="async" width="718" height="94" class="wp-image-7530" src="/wp-content/uploads/2018/06/word-image-136.png" srcset="/wp-content/uploads/2018/06/word-image-136.png 718w, /wp-content/uploads/2018/06/word-image-136-300x39.png 300w" sizes="(max-width: 718px) 100vw, 718px" /></p>
<h3>其中连贯操作方法</h3>
<ul>
<li>field(“field1,field2&#8230;”)：查询指定的字段field1和field2,多个用逗号隔开</li>
<li>alias(‘数据表别名’)：给当前数据表设置别名,join联表时用的多</li>
<li>where(查询条件)：查询条件可以为表达式查询、数组查询、字符串查询。</li>
<li>order(“field desc”)：把查询的到结果集进行字段field降序（desc）或升序(asc)。</li>
<li>group(“field”): 把查询的到结果集进行字段field分组。</li>
<li>limit(offset,length): 获取结果集指定条数的数据， offset为起始位置，length为获取记录的条数。</li>
<li>join()：与其他表进行关联查询</li>
</ul>
<p>注意：</p>
<p>以上的连贯操作方法都是返回当前模型的对象，即方法底层都是返回当前模型对象即return $this,所以他们之间的调用顺序不用按照原生的sql顺序来调用，但如果是查询数据，查询语句的最末端一定要确保是select或者是find方法。</p>
<p>例1：</p>
<p><img loading="lazy" decoding="async" width="989" height="116" class="wp-image-7531" src="/wp-content/uploads/2018/06/word-image-137.png" srcset="/wp-content/uploads/2018/06/word-image-137.png 989w, /wp-content/uploads/2018/06/word-image-137-300x35.png 300w, /wp-content/uploads/2018/06/word-image-137-768x90.png 768w" sizes="(max-width: 989px) 100vw, 989px" /></p>
<p>结果:</p>
<p><img loading="lazy" decoding="async" width="309" height="84" class="wp-image-7532" src="/wp-content/uploads/2018/06/word-image-138.png" srcset="/wp-content/uploads/2018/06/word-image-138.png 309w, /wp-content/uploads/2018/06/word-image-138-300x82.png 300w" sizes="(max-width: 309px) 100vw, 309px" /></p>
<p>注：通过模型数据对象-&gt;toArray()；可以转化为关联数组，看起来更加直观。</p>
<p>例2：</p>
<p><img loading="lazy" decoding="async" width="901" height="109" class="wp-image-7533" src="/wp-content/uploads/2018/06/word-image-139.png" srcset="/wp-content/uploads/2018/06/word-image-139.png 901w, /wp-content/uploads/2018/06/word-image-139-300x36.png 300w, /wp-content/uploads/2018/06/word-image-139-768x93.png 768w" sizes="(max-width: 901px) 100vw, 901px" /></p>
<p>例3：</p>
<p><img loading="lazy" decoding="async" width="925" height="105" class="wp-image-7534" src="/wp-content/uploads/2018/06/word-image-140.png" srcset="/wp-content/uploads/2018/06/word-image-140.png 925w, /wp-content/uploads/2018/06/word-image-140-300x34.png 300w, /wp-content/uploads/2018/06/word-image-140-768x87.png 768w" sizes="(max-width: 925px) 100vw, 925px" /></p>
<p>结果：</p>
<p><img loading="lazy" decoding="async" width="505" height="509" class="wp-image-7535" src="/wp-content/uploads/2018/06/word-image-141.png" srcset="/wp-content/uploads/2018/06/word-image-141.png 505w, /wp-content/uploads/2018/06/word-image-141-150x150.png 150w, /wp-content/uploads/2018/06/word-image-141-298x300.png 298w" sizes="(max-width: 505px) 100vw, 505px" /></p>
<p>默认select方法返回数组对象集合，只有取出具体的数据对象才可以调用toArray()转化为关联数组，如何把select方法的返回结果直接变为关联数组？</p>
<p>解决办法：把applciation/database.php文件的以下配置返回结果设置为think\Collection</p>
<p><img loading="lazy" decoding="async" width="747" height="187" class="wp-image-7536" src="/wp-content/uploads/2018/06/word-image-142.png" srcset="/wp-content/uploads/2018/06/word-image-142.png 747w, /wp-content/uploads/2018/06/word-image-142-300x75.png 300w" sizes="(max-width: 747px) 100vw, 747px" /></p>
<p>这样就可以使用select调用toAarray()返回关联数组：</p>
<p><img loading="lazy" decoding="async" width="1088" height="144" class="wp-image-7537" src="/wp-content/uploads/2018/06/word-image-143.png" srcset="/wp-content/uploads/2018/06/word-image-143.png 1088w, /wp-content/uploads/2018/06/word-image-143-300x40.png 300w, /wp-content/uploads/2018/06/word-image-143-768x102.png 768w, /wp-content/uploads/2018/06/word-image-143-1024x136.png 1024w" sizes="(max-width: 1088px) 100vw, 1088px" /></p>
<p><img loading="lazy" decoding="async" width="402" height="189" class="wp-image-7538" src="/wp-content/uploads/2018/06/word-image-144.png" srcset="/wp-content/uploads/2018/06/word-image-144.png 402w, /wp-content/uploads/2018/06/word-image-144-300x141.png 300w" sizes="(max-width: 402px) 100vw, 402px" /></p>
<p>例4、join联表</p>
<ol>
<li>联表查询出分类的所属父分类：</li>
</ol>
<p><img loading="lazy" decoding="async" width="1046" height="462" class="wp-image-7539" src="/wp-content/uploads/2018/06/word-image-145.png" srcset="/wp-content/uploads/2018/06/word-image-145.png 1046w, /wp-content/uploads/2018/06/word-image-145-300x133.png 300w, /wp-content/uploads/2018/06/word-image-145-768x339.png 768w, /wp-content/uploads/2018/06/word-image-145-1024x452.png 1024w" sizes="(max-width: 1046px) 100vw, 1046px" /></p>
<p>使用模型的join方法来实现：</p>
<p>手册位置：数据库&#8211;&gt;查询构造器&#8211;&gt;链式操作&#8211;&gt;join</p>
<p>语法： <img loading="lazy" decoding="async" width="674" height="55" class="wp-image-7540" src="/wp-content/uploads/2018/06/word-image-146.png" srcset="/wp-content/uploads/2018/06/word-image-146.png 674w, /wp-content/uploads/2018/06/word-image-146-300x24.png 300w" sizes="(max-width: 674px) 100vw, 674px" /></p>
<p><img loading="lazy" decoding="async" width="866" height="288" class="wp-image-7541" src="/wp-content/uploads/2018/06/word-image-147.png" srcset="/wp-content/uploads/2018/06/word-image-147.png 866w, /wp-content/uploads/2018/06/word-image-147-300x100.png 300w, /wp-content/uploads/2018/06/word-image-147-768x255.png 768w" sizes="(max-width: 866px) 100vw, 866px" /></p>
<p>结果：</p>
<p><img loading="lazy" decoding="async" width="492" height="409" class="wp-image-7542" src="/wp-content/uploads/2018/06/word-image-148.png" srcset="/wp-content/uploads/2018/06/word-image-148.png 492w, /wp-content/uploads/2018/06/word-image-148-300x249.png 300w" sizes="(max-width: 492px) 100vw, 492px" /></p>
<ol>
<li>联表查询出文章的所属分类：</li>
</ol>
<p><img loading="lazy" decoding="async" width="1045" height="408" class="wp-image-7543" src="/wp-content/uploads/2018/06/word-image-149.png" srcset="/wp-content/uploads/2018/06/word-image-149.png 1045w, /wp-content/uploads/2018/06/word-image-149-300x117.png 300w, /wp-content/uploads/2018/06/word-image-149-768x300.png 768w, /wp-content/uploads/2018/06/word-image-149-1024x400.png 1024w" sizes="(max-width: 1045px) 100vw, 1045px" /></p>
<p>在模型中使用join进行联表</p>
<ol>
<li>给表tp_article建立表模型</li>
</ol>
<p><img loading="lazy" decoding="async" width="396" height="167" class="wp-image-7544" src="/wp-content/uploads/2018/06/word-image-150.png" srcset="/wp-content/uploads/2018/06/word-image-150.png 396w, /wp-content/uploads/2018/06/word-image-150-300x127.png 300w" sizes="(max-width: 396px) 100vw, 396px" /></p>
<p>b、联表</p>
<p><img loading="lazy" decoding="async" width="845" height="363" class="wp-image-7545" src="/wp-content/uploads/2018/06/word-image-151.png" srcset="/wp-content/uploads/2018/06/word-image-151.png 845w, /wp-content/uploads/2018/06/word-image-151-300x129.png 300w, /wp-content/uploads/2018/06/word-image-151-768x330.png 768w" sizes="(max-width: 845px) 100vw, 845px" /></p>
<p>结果：</p>
<p><img loading="lazy" decoding="async" width="453" height="526" class="wp-image-7546" src="/wp-content/uploads/2018/06/word-image-152.png" srcset="/wp-content/uploads/2018/06/word-image-152.png 453w, /wp-content/uploads/2018/06/word-image-152-258x300.png 258w" sizes="(max-width: 453px) 100vw, 453px" /></p>
<h2>6、聚合（统计）函数</h2>
<p>常用的有以下几个聚合（统计）函数</p>
<p><img loading="lazy" decoding="async" width="465" height="273" class="wp-image-7547" src="/wp-content/uploads/2018/06/word-image-153.png" srcset="/wp-content/uploads/2018/06/word-image-153.png 465w, /wp-content/uploads/2018/06/word-image-153-300x176.png 300w" sizes="(max-width: 465px) 100vw, 465px" /></p>
<p>注意:调用统计函数前均支持连贯方法操作，但必须保证最末端是统计函数。</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="897" height="438" class="wp-image-7548" src="/wp-content/uploads/2018/06/word-image-154.png" srcset="/wp-content/uploads/2018/06/word-image-154.png 897w, /wp-content/uploads/2018/06/word-image-154-300x146.png 300w, /wp-content/uploads/2018/06/word-image-154-768x375.png 768w" sizes="(max-width: 897px) 100vw, 897px" /></p>
<h2>模型完成时间戳的自动维护</h2>
<p>手册位置：模型&#8211;&gt;时间戳</p>
<ol>
<li>给表设置update_time、create_time字段。</li>
</ol>
<p><img loading="lazy" decoding="async" width="519" height="195" class="wp-image-7549" src="/wp-content/uploads/2018/06/word-image-155.png" srcset="/wp-content/uploads/2018/06/word-image-155.png 519w, /wp-content/uploads/2018/06/word-image-155-300x113.png 300w" sizes="(max-width: 519px) 100vw, 519px" /></p>
<ol>
<li>在当前模型中开启时间戳的自动写入</li>
</ol>
<p><img loading="lazy" decoding="async" width="889" height="289" class="wp-image-7550" src="/wp-content/uploads/2018/06/word-image-156.png" srcset="/wp-content/uploads/2018/06/word-image-156.png 889w, /wp-content/uploads/2018/06/word-image-156-300x98.png 300w, /wp-content/uploads/2018/06/word-image-156-768x250.png 768w" sizes="(max-width: 889px) 100vw, 889px" /></p>
<p>开启时间戳自动写入之后，只要使用模型完成新增或编辑的操作，就会对表的两个时间字段字段自动维护。</p>
<h1>十七、通过Db构造器操作数据库</h1>
<p>通Db构造器查询数据库无需实例化模型也可对数据进行curd操作。</p>
<p>手册位置：数据库&#8211;&gt;查询构造器</p>
<h2>查询数据-R</h2>
<ul>
<li>查询一条数据</li>
</ul>
<p>如：Db::table(&#8216;think_user&#8217;)-&gt;field(‘username,email’)-&gt;where(id,1)-&gt;find();</p>
<ul>
<li>查询多条数据</li>
</ul>
<p>如：Db::table(&#8216;think_user&#8217;)-&gt;where(id,1)-&gt;select();</p>
<p>如：Db::name(&#8216;user&#8217;)-&gt;order(‘id’,’desc’)-&gt;select(); #不带表前缀</p>
<p>注： Db::table()需要完整表名，带表前缀，DB::name()是不带表前缀,且他们都支持连贯操作方法，只需保证最末端是select或是find或统计函数。</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="755" height="245" class="wp-image-7551" src="/wp-content/uploads/2018/06/word-image-157.png" srcset="/wp-content/uploads/2018/06/word-image-157.png 755w, /wp-content/uploads/2018/06/word-image-157-300x97.png 300w" sizes="(max-width: 755px) 100vw, 755px" /></p>
<p>结果：</p>
<p><img loading="lazy" decoding="async" width="287" height="366" class="wp-image-7552" src="/wp-content/uploads/2018/06/word-image-158.png" srcset="/wp-content/uploads/2018/06/word-image-158.png 287w, /wp-content/uploads/2018/06/word-image-158-235x300.png 235w" sizes="(max-width: 287px) 100vw, 287px" /></p>
<h2>执行原生sql语句</h2>
<p>查询：Db::query(“select”);</p>
<p>增删改：Db::execute(“insert/update/delete”);</p>
<p><img loading="lazy" decoding="async" width="925" height="90" class="wp-image-7553" src="/wp-content/uploads/2018/06/word-image-159.png" srcset="/wp-content/uploads/2018/06/word-image-159.png 925w, /wp-content/uploads/2018/06/word-image-159-300x29.png 300w, /wp-content/uploads/2018/06/word-image-159-768x75.png 768w" sizes="(max-width: 925px) 100vw, 925px" /></p>
<h2>添加数据-C</h2>
<ul>
<li>添加一条数据</li>
</ul>
<p>$data = [&#8216;foo&#8217; =&gt; &#8216;bar&#8217;, &#8216;bar&#8217; =&gt; &#8216;foo&#8217;];</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;insert($data);</p>
<p>insert 方法添加数据成功返回添加成功的条数，insert 正常情况返回 1</p>
<ul>
<li>或者直接使用insertGetId方法新增数据并返回主键值：</li>
</ul>
<p>Db::name(&#8216;user&#8217;)-&gt;insertGetId($data);</p>
<ul>
<li>添加多条数据</li>
</ul>
<p>添加多条数据直接向 Db 类的 insertAll 方法传入需要添加的数据即可</p>
<p>$data = [</p>
<p>[&#8216;foo&#8217; =&gt; &#8216;bar&#8217;, &#8216;bar&#8217; =&gt; &#8216;foo&#8217;],</p>
<p>[&#8216;foo&#8217; =&gt; &#8216;bar1&#8217;, &#8216;bar&#8217; =&gt; &#8216;foo1&#8217;],</p>
<p>[&#8216;foo&#8217; =&gt; &#8216;bar2&#8217;, &#8216;bar&#8217; =&gt; &#8216;foo2&#8217;]</p>
<p>];</p>
<p>Db::name(&#8216;user&#8217;)-&gt;insertAll($data);</p>
<p>insertAll 方法添加数据成功返回添加成功的条数</p>
<h2>删除数据-D</h2>
<ul>
<li>根据主键删除</li>
</ul>
<p>Db::table(&#8216;think_user&#8217;)-&gt;delete(1);</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;delete([1,2,3]);</p>
<ul>
<li>条件删除</li>
</ul>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;,1)-&gt;delete();</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;,'&lt;&#8216;,10)-&gt;delete();</p>
<p>delete 方法返回影响数据的条数，没有删除返回 0</p>
<h2>4、更新数据-U</h2>
<p>手册为主：数据库&#8211;&gt;查询构造器&#8211;&gt;更新数据</p>
<h3>更新数据表中的数据</h3>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;update([&#8216;name&#8217; =&gt; &#8216;thinkphp&#8217;]);</p>
<p>如果数据中包含主键，可以直接使用：</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;update([&#8216;name&#8217; =&gt; &#8216;thinkphp&#8217;,&#8217;id&#8217;=&gt;1]);</p>
<p>update 方法返回影响数据的条数，没修改任何数据返回 0</p>
<h3>更新某个字段的值</h3>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;,1)-&gt;setField(&#8216;name&#8217;, &#8216;thinkphp&#8217;);</p>
<p>setField 方法返回影响数据的条数，没修改任何数据字段返回 0</p>
<h3>自增或自减一个字段的值</h3>
<p>setInc/setDec 如不加第二个参数，默认值为1</p>
<p>// score 字段加 1</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;setInc(&#8216;score&#8217;);</p>
<p>// score 字段加 5</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;setInc(&#8216;score&#8217;, 5);</p>
<p>// score 字段减 1</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;setDec(&#8216;score&#8217;);</p>
<p>// score 字段减 5</p>
<p>Db::table(&#8216;think_user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;setDec(&#8216;score&#8217;, 5);</p>
<h3>助手db函数完成更新</h3>
<p>// 更新数据表中的数据</p>
<p>db(&#8216;user&#8217;)-&gt;where(&#8216;id&#8217;,1)-&gt;update([&#8216;name&#8217; =&gt; &#8216;thinkphp&#8217;]);</p>
<p>// 更新某个字段的值</p>
<p>db(&#8216;user&#8217;)-&gt;where(&#8216;id&#8217;,1)-&gt;setField(&#8216;name&#8217;,&#8217;thinkphp&#8217;);</p>
<p>// 自增 score 字段</p>
<p>db(&#8216;user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;setInc(&#8216;score&#8217;);</p>
<p>// 自减 score 字段</p>
<p>db(&#8216;user&#8217;)-&gt;where(&#8216;id&#8217;, 1)-&gt;setDec(&#8216;score&#8217;);</p>
<h1>完成后台登录功能</h1>
<p>般用户表的第一个用户都是自己手工添加的。</p>
<ol>
<li>在配置文件config.php中添加一个password_salt的配置</li>
</ol>
<p><img loading="lazy" decoding="async" width="703" height="301" class="wp-image-7554" src="/wp-content/uploads/2018/06/word-image-160.png" srcset="/wp-content/uploads/2018/06/word-image-160.png 703w, /wp-content/uploads/2018/06/word-image-160-300x128.png 300w" sizes="(max-width: 703px) 100vw, 703px" /></p>
<ol>
<li>把加密的结果复制到用户表的password字段中</li>
</ol>
<p><img loading="lazy" decoding="async" width="762" height="360" class="wp-image-7555" src="/wp-content/uploads/2018/06/word-image-161.png" srcset="/wp-content/uploads/2018/06/word-image-161.png 762w, /wp-content/uploads/2018/06/word-image-161-300x142.png 300w" sizes="(max-width: 762px) 100vw, 762px" /></p>
<ol>
<li>修改login.html登录表单</li>
</ol>
<p><img loading="lazy" decoding="async" width="1112" height="584" class="wp-image-7556" src="/wp-content/uploads/2018/06/word-image-162.png" srcset="/wp-content/uploads/2018/06/word-image-162.png 1112w, /wp-content/uploads/2018/06/word-image-162-300x158.png 300w, /wp-content/uploads/2018/06/word-image-162-768x403.png 768w, /wp-content/uploads/2018/06/word-image-162-1024x538.png 1024w" sizes="(max-width: 1112px) 100vw, 1112px" /></p>
<ol>
<li>在login方法中判断是post请求，完成入库</li>
</ol>
<p><img loading="lazy" decoding="async" width="748" height="651" class="wp-image-7557" src="/wp-content/uploads/2018/06/word-image-163.png" srcset="/wp-content/uploads/2018/06/word-image-163.png 748w, /wp-content/uploads/2018/06/word-image-163-300x261.png 300w" sizes="(max-width: 748px) 100vw, 748px" /></p>
<ol>
<li>在User模型中定义一个检出用户名和密码是否匹配的方法</li>
</ol>
<p><img loading="lazy" decoding="async" width="872" height="654" class="wp-image-7558" src="/wp-content/uploads/2018/06/word-image-164.png" srcset="/wp-content/uploads/2018/06/word-image-164.png 872w, /wp-content/uploads/2018/06/word-image-164-300x225.png 300w, /wp-content/uploads/2018/06/word-image-164-768x576.png 768w" sizes="(max-width: 872px) 100vw, 872px" /></p>
<p>登录成功后，把session中的用户名信息回显到后台首页中（top.html）</p>
<p><img loading="lazy" decoding="async" width="1239" height="291" class="wp-image-7559" src="/wp-content/uploads/2018/06/word-image-165.png" srcset="/wp-content/uploads/2018/06/word-image-165.png 1239w, /wp-content/uploads/2018/06/word-image-165-300x70.png 300w, /wp-content/uploads/2018/06/word-image-165-768x180.png 768w, /wp-content/uploads/2018/06/word-image-165-1024x241.png 1024w" sizes="(max-width: 1239px) 100vw, 1239px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="220" height="82" class="wp-image-7560" src="/wp-content/uploads/2018/06/word-image-166.png" /></p>
<h1>完成后台退出功能</h1>
<p>核心：清除登录成功写入的session信息即可</p>
<ol>
<li>在Public控制器中建立一个logout的方法，清除session</li>
</ol>
<p><img loading="lazy" decoding="async" width="545" height="482" class="wp-image-7561" src="/wp-content/uploads/2018/06/word-image-167.png" srcset="/wp-content/uploads/2018/06/word-image-167.png 545w, /wp-content/uploads/2018/06/word-image-167-300x265.png 300w" sizes="(max-width: 545px) 100vw, 545px" /></p>
<ol>
<li>修改top.html模板的退出链接地址</li>
</ol>
<p><img loading="lazy" decoding="async" width="1230" height="280" class="wp-image-7562" src="/wp-content/uploads/2018/06/word-image-168.png" srcset="/wp-content/uploads/2018/06/word-image-168.png 1230w, /wp-content/uploads/2018/06/word-image-168-300x68.png 300w, /wp-content/uploads/2018/06/word-image-168-768x175.png 768w, /wp-content/uploads/2018/06/word-image-168-1024x233.png 1024w" sizes="(max-width: 1230px) 100vw, 1230px" /></p>
<h1>二十、完成登录防翻墙</h1>
<p>核心思想： 建立一个公共的控制器如：CommonController,在此控制器中做权限验证，判断是否有没有session,其他需要验证用户登录session信息的控制器就需要继承此控制器即可。</p>
<p><img loading="lazy" decoding="async" width="1016" height="371" class="wp-image-7563" src="/wp-content/uploads/2018/06/word-image-169.png" srcset="/wp-content/uploads/2018/06/word-image-169.png 1016w, /wp-content/uploads/2018/06/word-image-169-300x110.png 300w, /wp-content/uploads/2018/06/word-image-169-768x280.png 768w" sizes="(max-width: 1016px) 100vw, 1016px" /></p>
<p>把需要验证session的后台index控制器继承Common控制器即可：</p>
<p><img loading="lazy" decoding="async" width="699" height="234" class="wp-image-7564" src="/wp-content/uploads/2018/06/word-image-170.png" srcset="/wp-content/uploads/2018/06/word-image-170.png 699w, /wp-content/uploads/2018/06/word-image-170-300x100.png 300w" sizes="(max-width: 699px) 100vw, 699px" /></p>
<p>注：Public控制器不可以继承，因为此时还没有session信息。</p>
<h1>二十一、完成登录验证</h1>
<p>概述：ThinkPHP5.0验证使用独立的\think\Validate类或者验证器进行验证。</p>
<p>手册位置：验证器。</p>
<p>手册示例：</p>
<p><img loading="lazy" decoding="async" width="475" height="614" class="wp-image-7565" src="/wp-content/uploads/2018/06/word-image-171.png" srcset="/wp-content/uploads/2018/06/word-image-171.png 475w, /wp-content/uploads/2018/06/word-image-171-232x300.png 232w" sizes="(max-width: 475px) 100vw, 475px" /></p>
<p>//定义验证规则语法：</p>
<p>$rule = [</p>
<p>‘表单name值’ =&gt; 规则（多个规则竖线|隔开）</p>
<p>]</p>
<p>//定义验证不通过的提示信息</p>
<p>$msg = [</p>
<p>‘表单name值.规则名’ =&gt; ‘此规则的不通过的提示信息’</p>
<p>]</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="791" height="706" class="wp-image-7566" src="/wp-content/uploads/2018/06/word-image-172.png" srcset="/wp-content/uploads/2018/06/word-image-172.png 791w, /wp-content/uploads/2018/06/word-image-172-300x268.png 300w, /wp-content/uploads/2018/06/word-image-172-768x685.png 768w" sizes="(max-width: 791px) 100vw, 791px" /></p>
<p>提示效果：</p>
<p><img loading="lazy" decoding="async" width="506" height="301" class="wp-image-7567" src="/wp-content/uploads/2018/06/word-image-173.png" srcset="/wp-content/uploads/2018/06/word-image-173.png 506w, /wp-content/uploads/2018/06/word-image-173-300x178.png 300w" sizes="(max-width: 506px) 100vw, 506px" /></p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7499.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5.0（三）Composer 安装验证码、登录验证码、AR 模式操作数据库、文章分类添加、文章分类列表展示、文章分类编辑、Ajax 无刷新分类删除、文章添加、富文本编辑器</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7568.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7568.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:42:59 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[Ajax 无刷新分类删除]]></category>
		<category><![CDATA[AR 模式操作数据库]]></category>
		<category><![CDATA[Composer 安装验证码]]></category>
		<category><![CDATA[富文本编辑器]]></category>
		<category><![CDATA[文章分类列表展示]]></category>
		<category><![CDATA[文章分类添加]]></category>
		<category><![CDATA[文章分类编辑]]></category>
		<category><![CDATA[文章添加]]></category>
		<category><![CDATA[登录验证码]]></category>
		<guid isPermaLink="false">/?p=7568</guid>

					<description><![CDATA[TP5第三天 composer 什么是composer Composer 是 PHP 的一个依赖管理工具。它允 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>TP5第三天</h1>
<h1>composer</h1>
<h2>什么是composer</h2>
<p>Composer 是 PHP 的一个依赖管理工具。它允许你申明项目所依赖的类库，它会在你的项目中为你安装他们。</p>
<p>假设有个文件A.php,我们项目中使用需要就include A.php 包含进来，但是A.php又基于B.php,所以我们在A.php文件中又需要include B,但是不幸的B.php又基于C.php和D.php,于是又要在B.php进行include C.php和D.php 。假设C和D文件又基于其他文件，那么这样互相依赖的引入是非常麻烦的。</p>
<p><img loading="lazy" decoding="async" width="881" height="132" class="wp-image-7569" src="/wp-content/uploads/2018/06/word-image-174.png" srcset="/wp-content/uploads/2018/06/word-image-174.png 881w, /wp-content/uploads/2018/06/word-image-174-300x45.png 300w, /wp-content/uploads/2018/06/word-image-174-768x115.png 768w" sizes="(max-width: 881px) 100vw, 881px" /></p>
<p>那么在项目中使用composer就可以解决各个文件互相依赖的问题。除了解决文件依赖的关系，它还有更多的优点：</p>
<ul>
<li>下载网络上我们项目所需要的类库。</li>
<li>可对下载的类库进行管理，如：删除、更新等众多便利的操作。</li>
</ul>
<p>其实composer也就类似与Linux中yum，前端中的npm、bower等操作。这些工具都是可以用来管理我们的代码的。</p>
<h2>安装composer</h2>
<p>安装方式一般有两种方式：</p>
<p>第一种：去composer官网( <a href="/goto/poxn" rel="nofollow">https://getcomposer.org/download/</a> )下载Composer-setup.exe进行安装，由于此软件安装需要联网且服务器在国外安装很难成功，所以这里推荐使用下面第二种方式进行安装。</p>
<p><img loading="lazy" decoding="async" width="520" height="174" class="wp-image-7570" src="/wp-content/uploads/2018/06/word-image-175.png" srcset="/wp-content/uploads/2018/06/word-image-175.png 520w, /wp-content/uploads/2018/06/word-image-175-300x100.png 300w" sizes="(max-width: 520px) 100vw, 520px" /></p>
<p>我们使用下面的安装方式</p>
<p>第二种：去官网https://getcomposer.org/download 下载composer.phar文件。</p>
<p><img loading="lazy" decoding="async" width="509" height="448" class="wp-image-7571" src="/wp-content/uploads/2018/06/word-image-176.png" srcset="/wp-content/uploads/2018/06/word-image-176.png 509w, /wp-content/uploads/2018/06/word-image-176-300x264.png 300w" sizes="(max-width: 509px) 100vw, 509px" /></p>
<p>找到并进入 PHP 的安装目录,将下载的composer.phar 复制到 PHP 的安装目录下面，也就是和 php.exe 在同一级目录。</p>
<p><img loading="lazy" decoding="async" width="715" height="462" class="wp-image-7572" src="/wp-content/uploads/2018/06/word-image-177.png" srcset="/wp-content/uploads/2018/06/word-image-177.png 715w, /wp-content/uploads/2018/06/word-image-177-300x194.png 300w" sizes="(max-width: 715px) 100vw, 715px" /></p>
<p>在 PHP 安装目录（D:\phpStudy\php\php-5.6.27-nts）下新建一个 composer.bat 文件，并将下列代码保存到此文件中。</p>
<p>@php &#8220;%~dp0composer.phar&#8221; %*</p>
<p>至此composer的安装就完成。</p>
<p>进入目录D:\phpStudy\php\php-5.6.27-nts中输入composer指令，出现如下提示代表安装成功：</p>
<p><img loading="lazy" decoding="async" width="826" height="366" class="wp-image-7573" src="/wp-content/uploads/2018/06/word-image-178.png" srcset="/wp-content/uploads/2018/06/word-image-178.png 826w, /wp-content/uploads/2018/06/word-image-178-300x133.png 300w, /wp-content/uploads/2018/06/word-image-178-768x340.png 768w" sizes="(max-width: 826px) 100vw, 826px" /></p>
<p>为了可以全局（任意位置）访问composer，可以把php.exe的所在目录（D:\phpStudy\php\php-5.6.27-nts）定义在环境变量path选项中。</p>
<p><img loading="lazy" decoding="async" width="418" height="255" class="wp-image-7574" src="/wp-content/uploads/2018/06/word-image-179.png" srcset="/wp-content/uploads/2018/06/word-image-179.png 418w, /wp-content/uploads/2018/06/word-image-179-300x183.png 300w" sizes="(max-width: 418px) 100vw, 418px" /></p>
<p>设置好后输入php -v即可看到php版本号。</p>
<p><img loading="lazy" decoding="async" width="526" height="76" class="wp-image-7575" src="/wp-content/uploads/2018/06/word-image-180.png" srcset="/wp-content/uploads/2018/06/word-image-180.png 526w, /wp-content/uploads/2018/06/word-image-180-300x43.png 300w" sizes="(max-width: 526px) 100vw, 526px" /></p>
<p>cmd中任意位置输入composer指令：</p>
<p><img loading="lazy" decoding="async" width="513" height="114" class="wp-image-7576" src="/wp-content/uploads/2018/06/word-image-181.png" srcset="/wp-content/uploads/2018/06/word-image-181.png 513w, /wp-content/uploads/2018/06/word-image-181-300x67.png 300w" sizes="(max-width: 513px) 100vw, 513px" /></p>
<h2>配置composer为国内镜像</h2>
<p>由于composer需要去网址为https://packagist.org获取代码库地址，再通过地址去github上去下载代码到我们项目本地，由于这两个地址服务器都在国外，访问比较慢，也不稳定。/</p>
<p><img loading="lazy" decoding="async" width="674" height="360" class="wp-image-7577" src="/wp-content/uploads/2018/06/word-image-182.png" srcset="/wp-content/uploads/2018/06/word-image-182.png 674w, /wp-content/uploads/2018/06/word-image-182-300x160.png 300w" sizes="(max-width: 674px) 100vw, 674px" /></p>
<p>配置国内镜像：输入命令</p>
<p>全局配置：composer config -g repo.packagist composer https://packagist.phpcomposer.com/</p>
<p><img loading="lazy" decoding="async" width="782" height="116" class="wp-image-7578" src="/wp-content/uploads/2018/06/word-image-183.png" srcset="/wp-content/uploads/2018/06/word-image-183.png 782w, /wp-content/uploads/2018/06/word-image-183-300x45.png 300w, /wp-content/uploads/2018/06/word-image-183-768x114.png 768w" sizes="(max-width: 782px) 100vw, 782px" /></p>
<p>局部配置：若只想在当前项目中有效，把上面的命令去掉 -g 即可。</p>
<p>几个有关的composer命令：</p>
<p>查看全局配置信息：composer config -gl</p>
<p>取消镜像：composer config -g &#8211;unset repos.packagist</p>
<p>查看当前版本：composer -v</p>
<p>升级版本：composer selfupdate</p>
<h1>使用composer安装tp5验证码</h1>
<p>手册位置：杂项&#8211;&gt;验证码</p>
<p>composer.json的文件说明和具体使用：</p>
<p>参考网址：http://docs.phpcomposer.com/04-schema.html#archive</p>
<p>第一步：切换到tp5的composer.json 所在的目录，输入指令 composer require topthink/think-captcha进行安装</p>
<p>在当前目录打开cmd：ctrl+shfit+鼠标右键</p>
<p><img loading="lazy" decoding="async" width="356" height="49" class="wp-image-7579" src="/wp-content/uploads/2018/06/word-image-184.png" srcset="/wp-content/uploads/2018/06/word-image-184.png 356w, /wp-content/uploads/2018/06/word-image-184-300x41.png 300w" sizes="(max-width: 356px) 100vw, 356px" /></p>
<p><img loading="lazy" decoding="async" width="712" height="328" class="wp-image-7580" src="/wp-content/uploads/2018/06/word-image-185.png" srcset="/wp-content/uploads/2018/06/word-image-185.png 712w, /wp-content/uploads/2018/06/word-image-185-300x138.png 300w" sizes="(max-width: 712px) 100vw, 712px" /></p>
<p>安装成功后，会在vendor目录多出think-captcha</p>
<p><img loading="lazy" decoding="async" width="701" height="283" class="wp-image-7581" src="/wp-content/uploads/2018/06/word-image-186.png" srcset="/wp-content/uploads/2018/06/word-image-186.png 701w, /wp-content/uploads/2018/06/word-image-186-300x121.png 300w" sizes="(max-width: 701px) 100vw, 701px" /></p>
<p>注：默认下载的tp5框架已经帮我们下载好了验证码，直接使用即可。</p>
<h1>完成登录的验证码功能</h1>
<p>我们需要把通过composer下载下来的验证码应用到我们tp5项目中。</p>
<p>手册位置：杂项&#8211;&gt;验证码</p>
<p>或：<a href="/goto/8fls" rel="nofollow">https://packagist.org/packages/topthink/think-captcha</a></p>
<p>第一步：在login.html显示验证码</p>
<p><img loading="lazy" decoding="async" width="1172" height="519" class="wp-image-7582" src="/wp-content/uploads/2018/06/word-image-187.png" srcset="/wp-content/uploads/2018/06/word-image-187.png 1172w, /wp-content/uploads/2018/06/word-image-187-300x133.png 300w, /wp-content/uploads/2018/06/word-image-187-768x340.png 768w, /wp-content/uploads/2018/06/word-image-187-1024x453.png 1024w" sizes="(max-width: 1172px) 100vw, 1172px" /></p>
<p>第二步：通过配置定义验证码的显示配置</p>
<p><img loading="lazy" decoding="async" width="731" height="422" class="wp-image-7583" src="/wp-content/uploads/2018/06/word-image-188.png" srcset="/wp-content/uploads/2018/06/word-image-188.png 731w, /wp-content/uploads/2018/06/word-image-188-300x173.png 300w" sizes="(max-width: 731px) 100vw, 731px" /></p>
<p>第三步：登录时，判断验证码是否匹配成功</p>
<p><img loading="lazy" decoding="async" width="771" height="629" class="wp-image-7584" src="/wp-content/uploads/2018/06/word-image-189.png" srcset="/wp-content/uploads/2018/06/word-image-189.png 771w, /wp-content/uploads/2018/06/word-image-189-300x245.png 300w, /wp-content/uploads/2018/06/word-image-189-768x627.png 768w" sizes="(max-width: 771px) 100vw, 771px" /></p>
<h1>四、AR模式操作数据库</h1>
<h2>1、AR介绍</h2>
<p>Active Record (AR) 模式 是一个流行的 对象-关系映射 (ORM) 技术。 每个 AR 类代表一个数据表（或视图），数据表（或视图）的列在 AR 类中体现为类的属性，一个 AR 实例则表示表中的一行。 常见的 CRUD 操作作为 AR 的方法实现。因此，我们可以以一种更加面向对象的方式操作数据库。</p>
<p>AR模式三个核心：</p>
<p>表&#8211;&gt;模型类</p>
<p>表中一行&#8211;&gt;模型对象</p>
<p>行的某列&#8211;&gt;模型对象属性</p>
<p><img loading="lazy" decoding="async" width="616" height="259" class="wp-image-7585" src="/wp-content/uploads/2018/06/word-image-190.png" srcset="/wp-content/uploads/2018/06/word-image-190.png 616w, /wp-content/uploads/2018/06/word-image-190-300x126.png 300w" sizes="(max-width: 616px) 100vw, 616px" /></p>
<h2>AR模式完成CURD操作</h2>
<h3>AR完成新增</h3>
<p>手册示例：</p>
<p><img loading="lazy" decoding="async" width="397" height="207" class="wp-image-7586" src="/wp-content/uploads/2018/06/word-image-191.png" srcset="/wp-content/uploads/2018/06/word-image-191.png 397w, /wp-content/uploads/2018/06/word-image-191-300x156.png 300w" sizes="(max-width: 397px) 100vw, 397px" /></p>
<p><img loading="lazy" decoding="async" width="577" height="238" class="wp-image-7587" src="/wp-content/uploads/2018/06/word-image-192.png" srcset="/wp-content/uploads/2018/06/word-image-192.png 577w, /wp-content/uploads/2018/06/word-image-192-300x124.png 300w" sizes="(max-width: 577px) 100vw, 577px" /></p>
<h3>AR完成删除</h3>
<p>手册示例：</p>
<p><img loading="lazy" decoding="async" width="456" height="146" class="wp-image-7588" src="/wp-content/uploads/2018/06/word-image-193.png" srcset="/wp-content/uploads/2018/06/word-image-193.png 456w, /wp-content/uploads/2018/06/word-image-193-300x96.png 300w" sizes="(max-width: 456px) 100vw, 456px" /></p>
<p><img loading="lazy" decoding="async" width="589" height="174" class="wp-image-7589" src="/wp-content/uploads/2018/06/word-image-194.png" srcset="/wp-content/uploads/2018/06/word-image-194.png 589w, /wp-content/uploads/2018/06/word-image-194-300x89.png 300w" sizes="(max-width: 589px) 100vw, 589px" /></p>
<h3>AR完成更新</h3>
<p><img loading="lazy" decoding="async" width="630" height="276" class="wp-image-7590" src="/wp-content/uploads/2018/06/word-image-195.png" srcset="/wp-content/uploads/2018/06/word-image-195.png 630w, /wp-content/uploads/2018/06/word-image-195-300x131.png 300w" sizes="(max-width: 630px) 100vw, 630px" /></p>
<h3>AR完成查询</h3>
<p><img loading="lazy" decoding="async" width="517" height="248" class="wp-image-7591" src="/wp-content/uploads/2018/06/word-image-196.png" srcset="/wp-content/uploads/2018/06/word-image-196.png 517w, /wp-content/uploads/2018/06/word-image-196-300x144.png 300w" sizes="(max-width: 517px) 100vw, 517px" /></p>
<h1>完成文章分类的添加</h1>
<h2>1、完成模板数据的展示</h2>
<p>第一步：修改后台的链接地址（left.html）</p>
<p><img loading="lazy" decoding="async" width="1254" height="314" class="wp-image-7592" src="/wp-content/uploads/2018/06/word-image-197.png" srcset="/wp-content/uploads/2018/06/word-image-197.png 1254w, /wp-content/uploads/2018/06/word-image-197-300x75.png 300w, /wp-content/uploads/2018/06/word-image-197-768x192.png 768w, /wp-content/uploads/2018/06/word-image-197-1024x256.png 1024w" sizes="(max-width: 1254px) 100vw, 1254px" /></p>
<p>第二步:在后台admin建立一个Category的控制器，并建立一个add方法完成添加分类的功能</p>
<p><img loading="lazy" decoding="async" width="921" height="410" class="wp-image-7593" src="/wp-content/uploads/2018/06/word-image-198.png" srcset="/wp-content/uploads/2018/06/word-image-198.png 921w, /wp-content/uploads/2018/06/word-image-198-300x134.png 300w, /wp-content/uploads/2018/06/word-image-198-768x342.png 768w" sizes="(max-width: 921px) 100vw, 921px" /></p>
<p>第三步：在当前模型的中，建立一个无限极分类的函数，完成栏目之间额层级缩进</p>
<p><img loading="lazy" decoding="async" width="1091" height="585" class="wp-image-7594" src="/wp-content/uploads/2018/06/word-image-199.png" srcset="/wp-content/uploads/2018/06/word-image-199.png 1091w, /wp-content/uploads/2018/06/word-image-199-300x161.png 300w, /wp-content/uploads/2018/06/word-image-199-768x412.png 768w, /wp-content/uploads/2018/06/word-image-199-1024x549.png 1024w" sizes="(max-width: 1091px) 100vw, 1091px" /></p>
<p>第四步：模板中显示数据</p>
<p><img loading="lazy" decoding="async" width="1241" height="604" class="wp-image-7595" src="/wp-content/uploads/2018/06/word-image-200.png" srcset="/wp-content/uploads/2018/06/word-image-200.png 1241w, /wp-content/uploads/2018/06/word-image-200-300x146.png 300w, /wp-content/uploads/2018/06/word-image-200-768x374.png 768w, /wp-content/uploads/2018/06/word-image-200-1024x498.png 1024w" sizes="(max-width: 1241px) 100vw, 1241px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="700" height="359" class="wp-image-7596" src="/wp-content/uploads/2018/06/word-image-201.png" srcset="/wp-content/uploads/2018/06/word-image-201.png 700w, /wp-content/uploads/2018/06/word-image-201-300x154.png 300w" sizes="(max-width: 700px) 100vw, 700px" /></p>
<h2>完成数据的入库</h2>
<p>第一步：在add方法中判断是否是post请求，完成数据的入库</p>
<p><img loading="lazy" decoding="async" width="799" height="662" class="wp-image-7597" src="/wp-content/uploads/2018/06/word-image-202.png" srcset="/wp-content/uploads/2018/06/word-image-202.png 799w, /wp-content/uploads/2018/06/word-image-202-300x249.png 300w, /wp-content/uploads/2018/06/word-image-202-768x636.png 768w" sizes="(max-width: 799px) 100vw, 799px" /></p>
<p>第二步：使用验证器Validate进行入库前的数据验证过滤</p>
<p><img loading="lazy" decoding="async" width="797" height="558" class="wp-image-7598" src="/wp-content/uploads/2018/06/word-image-203.png" srcset="/wp-content/uploads/2018/06/word-image-203.png 797w, /wp-content/uploads/2018/06/word-image-203-300x210.png 300w, /wp-content/uploads/2018/06/word-image-203-768x538.png 768w" sizes="(max-width: 797px) 100vw, 797px" /></p>
<p>建议把上面的验证写在一个验证器中，进行统计管理，也方便后期代码的维护，也可以增加代码的可读性。</p>
<p>所以，我们可以把上面的规则和提示信息抽离出来，写在独立的验证器中：</p>
<p><img loading="lazy" decoding="async" width="812" height="650" class="wp-image-7599" src="/wp-content/uploads/2018/06/word-image-204.png" srcset="/wp-content/uploads/2018/06/word-image-204.png 812w, /wp-content/uploads/2018/06/word-image-204-300x240.png 300w, /wp-content/uploads/2018/06/word-image-204-768x615.png 768w" sizes="(max-width: 812px) 100vw, 812px" /></p>
<p>在add的方法中使用上面的验证器进行验证即可：</p>
<p><img loading="lazy" decoding="async" width="1030" height="693" class="wp-image-7600" src="/wp-content/uploads/2018/06/word-image-205.png" srcset="/wp-content/uploads/2018/06/word-image-205.png 1030w, /wp-content/uploads/2018/06/word-image-205-300x202.png 300w, /wp-content/uploads/2018/06/word-image-205-768x517.png 768w, /wp-content/uploads/2018/06/word-image-205-1024x689.png 1024w" sizes="(max-width: 1030px) 100vw, 1030px" /></p>
<p>validate方法的源码位置：</p>
<p><img loading="lazy" decoding="async" width="1088" height="412" class="wp-image-7601" src="/wp-content/uploads/2018/06/word-image-206.png" srcset="/wp-content/uploads/2018/06/word-image-206.png 1088w, /wp-content/uploads/2018/06/word-image-206-300x114.png 300w, /wp-content/uploads/2018/06/word-image-206-768x291.png 768w, /wp-content/uploads/2018/06/word-image-206-1024x388.png 1024w" sizes="(max-width: 1088px) 100vw, 1088px" /></p>
<p>此方法验证成功会返回true。</p>
<p>验证失败会返回错误信息，若不是批量验证返回一个字符串的错误信息，批量验证则返回一个错误的数组，可以使用implode拼接成一个字符串进行提示。</p>
<h1>完成文章分类的列表展示</h1>
<p>第一步：修改left.html加一个链接地址</p>
<p><img loading="lazy" decoding="async" width="1257" height="257" class="wp-image-7602" src="/wp-content/uploads/2018/06/word-image-207.png" srcset="/wp-content/uploads/2018/06/word-image-207.png 1257w, /wp-content/uploads/2018/06/word-image-207-300x61.png 300w, /wp-content/uploads/2018/06/word-image-207-768x157.png 768w, /wp-content/uploads/2018/06/word-image-207-1024x209.png 1024w" sizes="(max-width: 1257px) 100vw, 1257px" /></p>
<p>第二步：在Category控制器加一个index 的方法完成分类的列表数据输出给模板</p>
<p><img loading="lazy" decoding="async" width="601" height="546" class="wp-image-7603" src="/wp-content/uploads/2018/06/word-image-208.png" srcset="/wp-content/uploads/2018/06/word-image-208.png 601w, /wp-content/uploads/2018/06/word-image-208-300x273.png 300w" sizes="(max-width: 601px) 100vw, 601px" /></p>
<p>其中$newlists的数据打印如下：以每个元素cat_id作为下标。</p>
<p><img loading="lazy" decoding="async" width="439" height="254" class="wp-image-7604" src="/wp-content/uploads/2018/06/word-image-209.png" srcset="/wp-content/uploads/2018/06/word-image-209.png 439w, /wp-content/uploads/2018/06/word-image-209-300x174.png 300w" sizes="(max-width: 439px) 100vw, 439px" /></p>
<p>第三步：模板中显示数据</p>
<p><img loading="lazy" decoding="async" width="1262" height="696" class="wp-image-7605" src="/wp-content/uploads/2018/06/word-image-210.png" srcset="/wp-content/uploads/2018/06/word-image-210.png 1262w, /wp-content/uploads/2018/06/word-image-210-300x165.png 300w, /wp-content/uploads/2018/06/word-image-210-768x424.png 768w, /wp-content/uploads/2018/06/word-image-210-1024x565.png 1024w" sizes="(max-width: 1262px) 100vw, 1262px" /></p>
<p>上面的由于数组$lists下标0不存在，所以需要isset判断一下，但是这样写较麻烦，可以通过配置不报这种错误。修改common.php即可。</p>
<p><img loading="lazy" decoding="async" width="811" height="293" class="wp-image-7606" src="/wp-content/uploads/2018/06/word-image-211.png" srcset="/wp-content/uploads/2018/06/word-image-211.png 811w, /wp-content/uploads/2018/06/word-image-211-300x108.png 300w, /wp-content/uploads/2018/06/word-image-211-768x277.png 768w" sizes="(max-width: 811px) 100vw, 811px" /></p>
<p>效果：<br />
<img loading="lazy" decoding="async" width="896" height="234" class="wp-image-7607" src="/wp-content/uploads/2018/06/word-image-212.png" srcset="/wp-content/uploads/2018/06/word-image-212.png 896w, /wp-content/uploads/2018/06/word-image-212-300x78.png 300w, /wp-content/uploads/2018/06/word-image-212-768x201.png 768w" sizes="(max-width: 896px) 100vw, 896px" /></p>
<p>注：其中create_time和update_time在数据库中是时间戳的格式，但是受到配置文件database.php 的影响，获取数据时，自动转化为日期格式：</p>
<p><img loading="lazy" decoding="async" width="856" height="256" class="wp-image-7608" src="/wp-content/uploads/2018/06/word-image-213.png" srcset="/wp-content/uploads/2018/06/word-image-213.png 856w, /wp-content/uploads/2018/06/word-image-213-300x90.png 300w, /wp-content/uploads/2018/06/word-image-213-768x230.png 768w" sizes="(max-width: 856px) 100vw, 856px" /></p>
<h1>完成文章分类的编辑</h1>
<p>第一步：修改列表的编辑的链接地址</p>
<p><img loading="lazy" decoding="async" width="1228" height="238" class="wp-image-7609" src="/wp-content/uploads/2018/06/word-image-214.png" srcset="/wp-content/uploads/2018/06/word-image-214.png 1228w, /wp-content/uploads/2018/06/word-image-214-300x58.png 300w, /wp-content/uploads/2018/06/word-image-214-768x149.png 768w, /wp-content/uploads/2018/06/word-image-214-1024x198.png 1024w" sizes="(max-width: 1228px) 100vw, 1228px" /></p>
<p>第二步：在Controller控制器建立一个upd方法，完成编辑的功能</p>
<p><img loading="lazy" decoding="async" width="820" height="716" class="wp-image-7610" src="/wp-content/uploads/2018/06/word-image-215.png" srcset="/wp-content/uploads/2018/06/word-image-215.png 820w, /wp-content/uploads/2018/06/word-image-215-300x262.png 300w, /wp-content/uploads/2018/06/word-image-215-768x671.png 768w" sizes="(max-width: 820px) 100vw, 820px" /></p>
<p>第三步：模板upd.html设置</p>
<p><img loading="lazy" decoding="async" width="1183" height="717" class="wp-image-7611" src="/wp-content/uploads/2018/06/word-image-216.png" srcset="/wp-content/uploads/2018/06/word-image-216.png 1183w, /wp-content/uploads/2018/06/word-image-216-300x182.png 300w, /wp-content/uploads/2018/06/word-image-216-768x465.png 768w, /wp-content/uploads/2018/06/word-image-216-1024x621.png 1024w" sizes="(max-width: 1183px) 100vw, 1183px" /></p>
<p>小技巧：$(&#8220;select[name=&#8217;pid&#8217;]&#8221;).val(3); //代表把option标签value等于3的父分类默认选中</p>
<p>当然也可以使用下面的eq来判断，但是不推荐，因为比较麻烦，而且还要模板标签还要编译效率低。</p>
<p><img loading="lazy" decoding="async" width="846" height="302" class="wp-image-7612" src="/wp-content/uploads/2018/06/word-image-217.png" srcset="/wp-content/uploads/2018/06/word-image-217.png 846w, /wp-content/uploads/2018/06/word-image-217-300x107.png 300w, /wp-content/uploads/2018/06/word-image-217-768x274.png 768w" sizes="(max-width: 846px) 100vw, 846px" /></p>
<h1>使用Ajax完成文章分类的无刷新删除</h1>
<h2>传统删除</h2>
<p>第一步：给删除设置链接地址</p>
<p><img loading="lazy" decoding="async" width="1259" height="278" class="wp-image-7613" src="/wp-content/uploads/2018/06/word-image-218.png" srcset="/wp-content/uploads/2018/06/word-image-218.png 1259w, /wp-content/uploads/2018/06/word-image-218-300x66.png 300w, /wp-content/uploads/2018/06/word-image-218-768x170.png 768w, /wp-content/uploads/2018/06/word-image-218-1024x226.png 1024w" sizes="(max-width: 1259px) 100vw, 1259px" /></p>
<p>第二步：在Category控制器建立一个del方法，完成分类的删除</p>
<p><img loading="lazy" decoding="async" width="777" height="337" class="wp-image-7614" src="/wp-content/uploads/2018/06/word-image-219.png" srcset="/wp-content/uploads/2018/06/word-image-219.png 777w, /wp-content/uploads/2018/06/word-image-219-300x130.png 300w, /wp-content/uploads/2018/06/word-image-219-768x333.png 768w" sizes="(max-width: 777px) 100vw, 777px" /></p>
<p>作业：删除分类考虑的两点</p>
<ol>
<li>当前分类下面是否有子分类</li>
<li>当前分类下面是否存在文章</li>
</ol>
<p>满足上面两个条件之一都不能删除。</p>
<h2>2、ajax无刷新删除</h2>
<p>删除分类考虑的两点</p>
<ol>
<li>当前分类下面是否有子分类</li>
<li>当前分类下面是否存在文章</li>
</ol>
<p>满足上面两个条件之一都不能删除。</p>
<p>第一步：给删除的a标签阻止默认行为，并且加一个自定义的属性cat_id,为了记录当前要删除的分类cat_id,同时设置一个delCat,目的给这一类的元素绑定单击事件</p>
<p><img loading="lazy" decoding="async" width="1253" height="210" class="wp-image-7615" src="/wp-content/uploads/2018/06/word-image-220.png" srcset="/wp-content/uploads/2018/06/word-image-220.png 1253w, /wp-content/uploads/2018/06/word-image-220-300x50.png 300w, /wp-content/uploads/2018/06/word-image-220-768x129.png 768w, /wp-content/uploads/2018/06/word-image-220-1024x172.png 1024w" sizes="(max-width: 1253px) 100vw, 1253px" /></p>
<p>第二步：给class=’delCat’,绑定单击事件，获取属性cat_id,发送ajax请求</p>
<p><img loading="lazy" decoding="async" width="1009" height="431" class="wp-image-7616" src="/wp-content/uploads/2018/06/word-image-221.png" srcset="/wp-content/uploads/2018/06/word-image-221.png 1009w, /wp-content/uploads/2018/06/word-image-221-300x128.png 300w, /wp-content/uploads/2018/06/word-image-221-768x328.png 768w" sizes="(max-width: 1009px) 100vw, 1009px" /></p>
<p>第三步：去Category控制器，建立一个ajaxDelCat的方法</p>
<p><img loading="lazy" decoding="async" width="842" height="715" class="wp-image-7617" src="/wp-content/uploads/2018/06/word-image-222.png" srcset="/wp-content/uploads/2018/06/word-image-222.png 842w, /wp-content/uploads/2018/06/word-image-222-300x255.png 300w, /wp-content/uploads/2018/06/word-image-222-768x652.png 768w" sizes="(max-width: 842px) 100vw, 842px" /></p>
<p>第四步：ajax根据服务端响应的json数据，删除成功把当前tr给移除掉</p>
<p><img loading="lazy" decoding="async" width="1000" height="605" class="wp-image-7618" src="/wp-content/uploads/2018/06/word-image-223.png" srcset="/wp-content/uploads/2018/06/word-image-223.png 1000w, /wp-content/uploads/2018/06/word-image-223-300x182.png 300w, /wp-content/uploads/2018/06/word-image-223-768x465.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<h1>完成文章的添加</h1>
<h2>完成文章模板的展示</h2>
<p>第一步：修改left.html模板，加一个添加分类的链接地址</p>
<p><img loading="lazy" decoding="async" width="1262" height="365" class="wp-image-7619" src="/wp-content/uploads/2018/06/word-image-224.png" srcset="/wp-content/uploads/2018/06/word-image-224.png 1262w, /wp-content/uploads/2018/06/word-image-224-300x87.png 300w, /wp-content/uploads/2018/06/word-image-224-768x222.png 768w, /wp-content/uploads/2018/06/word-image-224-1024x296.png 1024w" sizes="(max-width: 1262px) 100vw, 1262px" /></p>
<p>第二步：在后台admin创建一个Article控制器，并建立一个add方法，完成文章的入库操作</p>
<p><img loading="lazy" decoding="async" width="749" height="368" class="wp-image-7620" src="/wp-content/uploads/2018/06/word-image-225.png" srcset="/wp-content/uploads/2018/06/word-image-225.png 749w, /wp-content/uploads/2018/06/word-image-225-300x147.png 300w" sizes="(max-width: 749px) 100vw, 749px" /></p>
<p>模板分配数据：</p>
<p><img loading="lazy" decoding="async" width="670" height="389" class="wp-image-7621" src="/wp-content/uploads/2018/06/word-image-226.png" srcset="/wp-content/uploads/2018/06/word-image-226.png 670w, /wp-content/uploads/2018/06/word-image-226-300x174.png 300w" sizes="(max-width: 670px) 100vw, 670px" /></p>
<h2>使用富文本编辑器完成文章的内容添加</h2>
<p>第一步：把课件中的相应的ueditor复制到网站根目录下面的插件目录plugin中</p>
<p><img loading="lazy" decoding="async" width="771" height="251" class="wp-image-7622" src="/wp-content/uploads/2018/06/word-image-227.png" srcset="/wp-content/uploads/2018/06/word-image-227.png 771w, /wp-content/uploads/2018/06/word-image-227-300x98.png 300w, /wp-content/uploads/2018/06/word-image-227-768x250.png 768w" sizes="(max-width: 771px) 100vw, 771px" /></p>
<p>第二步：引入核心js文件，并且给textarea 设置一个id=content</p>
<p><img loading="lazy" decoding="async" width="1304" height="496" class="wp-image-7623" src="/wp-content/uploads/2018/06/word-image-228.png" srcset="/wp-content/uploads/2018/06/word-image-228.png 1304w, /wp-content/uploads/2018/06/word-image-228-300x114.png 300w, /wp-content/uploads/2018/06/word-image-228-768x292.png 768w, /wp-content/uploads/2018/06/word-image-228-1024x389.png 1024w" sizes="(max-width: 1304px) 100vw, 1304px" /></p>
<p><img loading="lazy" decoding="async" width="1277" height="556" class="wp-image-7624" src="/wp-content/uploads/2018/06/word-image-229.png" srcset="/wp-content/uploads/2018/06/word-image-229.png 1277w, /wp-content/uploads/2018/06/word-image-229-300x131.png 300w, /wp-content/uploads/2018/06/word-image-229-768x334.png 768w, /wp-content/uploads/2018/06/word-image-229-1024x446.png 1024w" sizes="(max-width: 1277px) 100vw, 1277px" /></p>
<p>效果如下：</p>
<p><img loading="lazy" decoding="async" width="1040" height="418" class="wp-image-7625" src="/wp-content/uploads/2018/06/word-image-230.png" srcset="/wp-content/uploads/2018/06/word-image-230.png 1040w, /wp-content/uploads/2018/06/word-image-230-300x121.png 300w, /wp-content/uploads/2018/06/word-image-230-768x309.png 768w, /wp-content/uploads/2018/06/word-image-230-1024x412.png 1024w" sizes="(max-width: 1040px) 100vw, 1040px" /></p>
<h2>完成文章数据的入库</h2>
<p>第一步：设置表单name值</p>
<p><img loading="lazy" decoding="async" width="1315" height="712" class="wp-image-7626" src="/wp-content/uploads/2018/06/word-image-231.png" srcset="/wp-content/uploads/2018/06/word-image-231.png 1315w, /wp-content/uploads/2018/06/word-image-231-300x162.png 300w, /wp-content/uploads/2018/06/word-image-231-768x416.png 768w, /wp-content/uploads/2018/06/word-image-231-1024x554.png 1024w" sizes="(max-width: 1315px) 100vw, 1315px" /></p>
<p>第二步：在add方法中，完成数据的入库</p>
<p><img loading="lazy" decoding="async" width="935" height="563" class="wp-image-7627" src="/wp-content/uploads/2018/06/word-image-232.png" srcset="/wp-content/uploads/2018/06/word-image-232.png 935w, /wp-content/uploads/2018/06/word-image-232-300x180.png 300w, /wp-content/uploads/2018/06/word-image-232-768x462.png 768w" sizes="(max-width: 935px) 100vw, 935px" /></p>
<h2>4、使用验证器完成添加文章的验证</h2>
<h2>5、完成文章的图片上传</h2>
<h2>6、完成文章图片缩略图生成</h2>
<h1>十、完成文章的列表展示</h1>
<h2>数据展示</h2>
<h2>2、数据分页</h2>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7568.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5.0（四）添加文章、添加验证、图片上传、缩略图、图片预览、文章列表展示、分页、文章编辑、文章删除、XSS 攻击、Jquery-Validate 验证插件、钩子函数</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7628.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7628.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:41:37 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[Jquery-Validate 验证插件]]></category>
		<category><![CDATA[XSS 攻击]]></category>
		<category><![CDATA[分页]]></category>
		<category><![CDATA[图片上传]]></category>
		<category><![CDATA[图片预览]]></category>
		<category><![CDATA[文章列表展示]]></category>
		<category><![CDATA[文章删除]]></category>
		<category><![CDATA[文章编辑]]></category>
		<category><![CDATA[添加文章]]></category>
		<category><![CDATA[添加验证]]></category>
		<category><![CDATA[缩略图]]></category>
		<category><![CDATA[钩子函数]]></category>
		<guid isPermaLink="false">/?p=7628</guid>

					<description><![CDATA[TP5第四天 一、完成文章的添加 完成文章模板的展示 第一步：修改left.html模板，加一个添加分类的链接 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>TP5第四天</h1>
<h1>一、完成文章的添加</h1>
<h2>完成文章模板的展示</h2>
<p>第一步：修改left.html模板，加一个添加分类的链接地址</p>
<p><img loading="lazy" decoding="async" width="1262" height="365" class="wp-image-7629" src="/wp-content/uploads/2018/06/word-image-233.png" srcset="/wp-content/uploads/2018/06/word-image-233.png 1262w, /wp-content/uploads/2018/06/word-image-233-300x87.png 300w, /wp-content/uploads/2018/06/word-image-233-768x222.png 768w, /wp-content/uploads/2018/06/word-image-233-1024x296.png 1024w" sizes="(max-width: 1262px) 100vw, 1262px" /></p>
<p>第二步：在后台admin创建一个Article控制器，并建立一个add方法，完成文章的入库操作</p>
<p><img loading="lazy" decoding="async" width="749" height="368" class="wp-image-7630" src="/wp-content/uploads/2018/06/word-image-234.png" srcset="/wp-content/uploads/2018/06/word-image-234.png 749w, /wp-content/uploads/2018/06/word-image-234-300x147.png 300w" sizes="(max-width: 749px) 100vw, 749px" /></p>
<p>模板分配数据：</p>
<p><img loading="lazy" decoding="async" width="670" height="389" class="wp-image-7631" src="/wp-content/uploads/2018/06/word-image-235.png" srcset="/wp-content/uploads/2018/06/word-image-235.png 670w, /wp-content/uploads/2018/06/word-image-235-300x174.png 300w" sizes="(max-width: 670px) 100vw, 670px" /></p>
<h2>使用富文本编辑器完成文章的内容添加</h2>
<p>第一步：把课件中的相应的ueditor复制到网站根目录下面的插件目录plugin中</p>
<p><img loading="lazy" decoding="async" width="771" height="251" class="wp-image-7632" src="/wp-content/uploads/2018/06/word-image-236.png" srcset="/wp-content/uploads/2018/06/word-image-236.png 771w, /wp-content/uploads/2018/06/word-image-236-300x98.png 300w, /wp-content/uploads/2018/06/word-image-236-768x250.png 768w" sizes="(max-width: 771px) 100vw, 771px" /></p>
<p>第二步：引入核心js文件，并且给textarea 设置一个id=content</p>
<p><img loading="lazy" decoding="async" width="1304" height="496" class="wp-image-7633" src="/wp-content/uploads/2018/06/word-image-237.png" srcset="/wp-content/uploads/2018/06/word-image-237.png 1304w, /wp-content/uploads/2018/06/word-image-237-300x114.png 300w, /wp-content/uploads/2018/06/word-image-237-768x292.png 768w, /wp-content/uploads/2018/06/word-image-237-1024x389.png 1024w" sizes="(max-width: 1304px) 100vw, 1304px" /></p>
<p><img loading="lazy" decoding="async" width="1277" height="556" class="wp-image-7634" src="/wp-content/uploads/2018/06/word-image-238.png" srcset="/wp-content/uploads/2018/06/word-image-238.png 1277w, /wp-content/uploads/2018/06/word-image-238-300x131.png 300w, /wp-content/uploads/2018/06/word-image-238-768x334.png 768w, /wp-content/uploads/2018/06/word-image-238-1024x446.png 1024w" sizes="(max-width: 1277px) 100vw, 1277px" /></p>
<p>效果如下：</p>
<p><img loading="lazy" decoding="async" width="1040" height="418" class="wp-image-7635" src="/wp-content/uploads/2018/06/word-image-239.png" srcset="/wp-content/uploads/2018/06/word-image-239.png 1040w, /wp-content/uploads/2018/06/word-image-239-300x121.png 300w, /wp-content/uploads/2018/06/word-image-239-768x309.png 768w, /wp-content/uploads/2018/06/word-image-239-1024x412.png 1024w" sizes="(max-width: 1040px) 100vw, 1040px" /></p>
<h2>完成文章数据的入库</h2>
<p>第一步：设置表单name值</p>
<p><img loading="lazy" decoding="async" width="1315" height="712" class="wp-image-7636" src="/wp-content/uploads/2018/06/word-image-240.png" srcset="/wp-content/uploads/2018/06/word-image-240.png 1315w, /wp-content/uploads/2018/06/word-image-240-300x162.png 300w, /wp-content/uploads/2018/06/word-image-240-768x416.png 768w, /wp-content/uploads/2018/06/word-image-240-1024x554.png 1024w" sizes="(max-width: 1315px) 100vw, 1315px" /></p>
<p>第二步：在add方法中，完成数据的入库</p>
<p><img loading="lazy" decoding="async" width="935" height="563" class="wp-image-7637" src="/wp-content/uploads/2018/06/word-image-241.png" srcset="/wp-content/uploads/2018/06/word-image-241.png 935w, /wp-content/uploads/2018/06/word-image-241-300x180.png 300w, /wp-content/uploads/2018/06/word-image-241-768x462.png 768w" sizes="(max-width: 935px) 100vw, 935px" /></p>
<h2>使用验证器完成添加文章的验证</h2>
<p>在后台的admin的validate目录建立一个Article 的验证器</p>
<p><img loading="lazy" decoding="async" width="853" height="503" class="wp-image-7638" src="/wp-content/uploads/2018/06/word-image-242.png" srcset="/wp-content/uploads/2018/06/word-image-242.png 853w, /wp-content/uploads/2018/06/word-image-242-300x177.png 300w, /wp-content/uploads/2018/06/word-image-242-768x453.png 768w" sizes="(max-width: 853px) 100vw, 853px" /></p>
<p>添加文章的时候，调用验证器的对应场景进行验证：</p>
<p><img loading="lazy" decoding="async" width="977" height="645" class="wp-image-7639" src="/wp-content/uploads/2018/06/word-image-243.png" srcset="/wp-content/uploads/2018/06/word-image-243.png 977w, /wp-content/uploads/2018/06/word-image-243-300x198.png 300w, /wp-content/uploads/2018/06/word-image-243-768x507.png 768w" sizes="(max-width: 977px) 100vw, 977px" /></p>
<h2>完成文章的图片上传</h2>
<p>表单上传文件的要求：1、post提交 2、设置form的enctype=’multipart/form-data’</p>
<p><img loading="lazy" decoding="async" width="747" height="155" class="wp-image-7640" src="/wp-content/uploads/2018/06/word-image-244.png" srcset="/wp-content/uploads/2018/06/word-image-244.png 747w, /wp-content/uploads/2018/06/word-image-244-300x62.png 300w" sizes="(max-width: 747px) 100vw, 747px" /></p>
<p>设置上传文件的input标签</p>
<p><img loading="lazy" decoding="async" width="882" height="213" class="wp-image-7641" src="/wp-content/uploads/2018/06/word-image-245.png" srcset="/wp-content/uploads/2018/06/word-image-245.png 882w, /wp-content/uploads/2018/06/word-image-245-300x72.png 300w, /wp-content/uploads/2018/06/word-image-245-768x185.png 768w" sizes="(max-width: 882px) 100vw, 882px" /></p>
<p>控制器add方法处理上传文件的路径入库：</p>
<p><img loading="lazy" decoding="async" width="1076" height="650" class="wp-image-7642" src="/wp-content/uploads/2018/06/word-image-246.png" srcset="/wp-content/uploads/2018/06/word-image-246.png 1076w, /wp-content/uploads/2018/06/word-image-246-300x180.png 300w, /wp-content/uploads/2018/06/word-image-246-768x464.png 768w, /wp-content/uploads/2018/06/word-image-246-1024x619.png 1024w" sizes="(max-width: 1076px) 100vw, 1076px" /></p>
<p>数据库存储的路径形式如下：</p>
<p><img loading="lazy" decoding="async" width="490" height="44" class="wp-image-7643" src="/wp-content/uploads/2018/06/word-image-247.png" srcset="/wp-content/uploads/2018/06/word-image-247.png 490w, /wp-content/uploads/2018/06/word-image-247-300x27.png 300w" sizes="(max-width: 490px) 100vw, 490px" /></p>
<h2>6、完成文章图片缩略图生成</h2>
<p>在有文件上传成功的前提下，处理缩略图生成：</p>
<p><img loading="lazy" decoding="async" width="1208" height="664" class="wp-image-7644" src="/wp-content/uploads/2018/06/word-image-248.png" srcset="/wp-content/uploads/2018/06/word-image-248.png 1208w, /wp-content/uploads/2018/06/word-image-248-300x165.png 300w, /wp-content/uploads/2018/06/word-image-248-768x422.png 768w, /wp-content/uploads/2018/06/word-image-248-1024x563.png 1024w" sizes="(max-width: 1208px) 100vw, 1208px" /></p>
<p>注：函数thumb(width，height,缩放比例) ，缩放比例默认为1为等比例缩放，为2则是填充补白。</p>
<p>存储如下：</p>
<p><img loading="lazy" decoding="async" width="394" height="139" class="wp-image-7645" src="/wp-content/uploads/2018/06/word-image-249.png" srcset="/wp-content/uploads/2018/06/word-image-249.png 394w, /wp-content/uploads/2018/06/word-image-249-300x106.png 300w" sizes="(max-width: 394px) 100vw, 394px" /></p>
<p>数据库存储的路径：</p>
<p><img loading="lazy" decoding="async" width="548" height="53" class="wp-image-7646" src="/wp-content/uploads/2018/06/word-image-250.png" srcset="/wp-content/uploads/2018/06/word-image-250.png 548w, /wp-content/uploads/2018/06/word-image-250-300x29.png 300w" sizes="(max-width: 548px) 100vw, 548px" /></p>
<h2>实现上传图片的实时预览</h2>
<p>引入核心js文件：</p>
<p><img loading="lazy" decoding="async" width="765" height="177" class="wp-image-7647" src="/wp-content/uploads/2018/06/word-image-251.png" srcset="/wp-content/uploads/2018/06/word-image-251.png 765w, /wp-content/uploads/2018/06/word-image-251-300x69.png 300w" sizes="(max-width: 765px) 100vw, 765px" /></p>
<p><img loading="lazy" decoding="async" width="1115" height="287" class="wp-image-7648" src="/wp-content/uploads/2018/06/word-image-252.png" srcset="/wp-content/uploads/2018/06/word-image-252.png 1115w, /wp-content/uploads/2018/06/word-image-252-300x77.png 300w, /wp-content/uploads/2018/06/word-image-252-768x198.png 768w, /wp-content/uploads/2018/06/word-image-252-1024x264.png 1024w" sizes="(max-width: 1115px) 100vw, 1115px" /></p>
<p>在add.html模板文件设置预览的区域：<br />
<img loading="lazy" decoding="async" width="1205" height="362" class="wp-image-7649" src="/wp-content/uploads/2018/06/word-image-253.png" srcset="/wp-content/uploads/2018/06/word-image-253.png 1205w, /wp-content/uploads/2018/06/word-image-253-300x90.png 300w, /wp-content/uploads/2018/06/word-image-253-768x231.png 768w, /wp-content/uploads/2018/06/word-image-253-1024x308.png 1024w" sizes="(max-width: 1205px) 100vw, 1205px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="554" height="367" class="wp-image-7650" src="/wp-content/uploads/2018/06/word-image-254.png" srcset="/wp-content/uploads/2018/06/word-image-254.png 554w, /wp-content/uploads/2018/06/word-image-254-300x199.png 300w" sizes="(max-width: 554px) 100vw, 554px" /></p>
<h1>完成文章的列表展示</h1>
<h2>数据展示</h2>
<p>第一步：在后台admin的Article控制器中建立一个index方法，完成文章列表展示</p>
<p><img loading="lazy" decoding="async" width="1003" height="370" class="wp-image-7651" src="/wp-content/uploads/2018/06/word-image-255.png" srcset="/wp-content/uploads/2018/06/word-image-255.png 1003w, /wp-content/uploads/2018/06/word-image-255-300x111.png 300w, /wp-content/uploads/2018/06/word-image-255-768x283.png 768w" sizes="(max-width: 1003px) 100vw, 1003px" /></p>
<p>模板中index.php,循环输出</p>
<p><img loading="lazy" decoding="async" width="1287" height="516" class="wp-image-7652" src="/wp-content/uploads/2018/06/word-image-256.png" srcset="/wp-content/uploads/2018/06/word-image-256.png 1287w, /wp-content/uploads/2018/06/word-image-256-300x120.png 300w, /wp-content/uploads/2018/06/word-image-256-768x308.png 768w, /wp-content/uploads/2018/06/word-image-256-1024x411.png 1024w" sizes="(max-width: 1287px) 100vw, 1287px" /></p>
<h2>数据分页</h2>
<p>把模型的select方法改为paginate(每页显示条数)即可</p>
<p><img loading="lazy" decoding="async" width="976" height="366" class="wp-image-7653" src="/wp-content/uploads/2018/06/word-image-257.png" srcset="/wp-content/uploads/2018/06/word-image-257.png 976w, /wp-content/uploads/2018/06/word-image-257-300x113.png 300w, /wp-content/uploads/2018/06/word-image-257-768x288.png 768w" sizes="(max-width: 976px) 100vw, 976px" /></p>
<p>模板中输出分页页码：</p>
<p><img loading="lazy" decoding="async" width="1072" height="636" class="wp-image-7654" src="/wp-content/uploads/2018/06/word-image-258.png" srcset="/wp-content/uploads/2018/06/word-image-258.png 1072w, /wp-content/uploads/2018/06/word-image-258-300x178.png 300w, /wp-content/uploads/2018/06/word-image-258-768x456.png 768w, /wp-content/uploads/2018/06/word-image-258-1024x608.png 1024w" sizes="(max-width: 1072px) 100vw, 1072px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="581" height="249" class="wp-image-7655" src="/wp-content/uploads/2018/06/word-image-259.png" srcset="/wp-content/uploads/2018/06/word-image-259.png 581w, /wp-content/uploads/2018/06/word-image-259-300x129.png 300w" sizes="(max-width: 581px) 100vw, 581px" /></p>
<h1>完成文章编辑</h1>
<p>第一步：给编辑设置链接地址，携带文章的参数id</p>
<p><img loading="lazy" decoding="async" width="1304" height="235" class="wp-image-7656" src="/wp-content/uploads/2018/06/word-image-260.png" srcset="/wp-content/uploads/2018/06/word-image-260.png 1304w, /wp-content/uploads/2018/06/word-image-260-300x54.png 300w, /wp-content/uploads/2018/06/word-image-260-768x138.png 768w, /wp-content/uploads/2018/06/word-image-260-1024x185.png 1024w" sizes="(max-width: 1304px) 100vw, 1304px" /></p>
<p>第二步：建立一个upd方法完成数据回显到模板中</p>
<p><img loading="lazy" decoding="async" width="848" height="400" class="wp-image-7657" src="/wp-content/uploads/2018/06/word-image-261.png" srcset="/wp-content/uploads/2018/06/word-image-261.png 848w, /wp-content/uploads/2018/06/word-image-261-300x142.png 300w, /wp-content/uploads/2018/06/word-image-261-768x362.png 768w" sizes="(max-width: 848px) 100vw, 848px" /></p>
<p>第三步：模板中回显数据</p>
<p><img loading="lazy" decoding="async" width="1226" height="660" class="wp-image-7658" src="/wp-content/uploads/2018/06/word-image-262.png" srcset="/wp-content/uploads/2018/06/word-image-262.png 1226w, /wp-content/uploads/2018/06/word-image-262-300x162.png 300w, /wp-content/uploads/2018/06/word-image-262-768x413.png 768w, /wp-content/uploads/2018/06/word-image-262-1024x551.png 1024w" sizes="(max-width: 1226px) 100vw, 1226px" /></p>
<p><img loading="lazy" decoding="async" width="922" height="352" class="wp-image-7659" src="/wp-content/uploads/2018/06/word-image-263.png" srcset="/wp-content/uploads/2018/06/word-image-263.png 922w, /wp-content/uploads/2018/06/word-image-263-300x115.png 300w, /wp-content/uploads/2018/06/word-image-263-768x293.png 768w" sizes="(max-width: 922px) 100vw, 922px" /></p>
<p>效果：<br />
<img loading="lazy" decoding="async" width="516" height="399" class="wp-image-7660" src="/wp-content/uploads/2018/06/word-image-264.png" srcset="/wp-content/uploads/2018/06/word-image-264.png 516w, /wp-content/uploads/2018/06/word-image-264-300x232.png 300w" sizes="(max-width: 516px) 100vw, 516px" /></p>
<p>第四步：在upd方法中判断是否是post请求，完成数据的编辑入库</p>
<p><img loading="lazy" decoding="async" width="725" height="671" class="wp-image-7661" src="/wp-content/uploads/2018/06/word-image-265.png" srcset="/wp-content/uploads/2018/06/word-image-265.png 725w, /wp-content/uploads/2018/06/word-image-265-300x278.png 300w" sizes="(max-width: 725px) 100vw, 725px" /></p>
<p>可以设置Article模型自动维护时间戳：<br />
<img loading="lazy" decoding="async" width="504" height="236" class="wp-image-7662" src="/wp-content/uploads/2018/06/word-image-266.png" srcset="/wp-content/uploads/2018/06/word-image-266.png 504w, /wp-content/uploads/2018/06/word-image-266-300x140.png 300w" sizes="(max-width: 504px) 100vw, 504px" /></p>
<h1>完成文章删除</h1>
<p>第一步：给删除的链接地址设置链接，并且设置参数</p>
<p><img loading="lazy" decoding="async" width="1249" height="475" class="wp-image-7663" src="/wp-content/uploads/2018/06/word-image-267.png" srcset="/wp-content/uploads/2018/06/word-image-267.png 1249w, /wp-content/uploads/2018/06/word-image-267-300x114.png 300w, /wp-content/uploads/2018/06/word-image-267-768x292.png 768w, /wp-content/uploads/2018/06/word-image-267-1024x389.png 1024w" sizes="(max-width: 1249px) 100vw, 1249px" /></p>
<p>第二步：添加del方法完成删除</p>
<p><img loading="lazy" decoding="async" width="942" height="544" class="wp-image-7664" src="/wp-content/uploads/2018/06/word-image-268.png" srcset="/wp-content/uploads/2018/06/word-image-268.png 942w, /wp-content/uploads/2018/06/word-image-268-300x173.png 300w, /wp-content/uploads/2018/06/word-image-268-768x444.png 768w" sizes="(max-width: 942px) 100vw, 942px" /></p>
<h1>五、XSS攻击</h1>
<h2>xss介绍</h2>
<p><img loading="lazy" decoding="async" width="830" height="141" class="wp-image-7665" src="/wp-content/uploads/2018/06/word-image-269.png" srcset="/wp-content/uploads/2018/06/word-image-269.png 830w, /wp-content/uploads/2018/06/word-image-269-300x51.png 300w, /wp-content/uploads/2018/06/word-image-269-768x130.png 768w" sizes="(max-width: 830px) 100vw, 830px" /></p>
<p>如在输入框输入js代码：</p>
<p><img loading="lazy" decoding="async" width="551" height="67" class="wp-image-7666" src="/wp-content/uploads/2018/06/word-image-270.png" srcset="/wp-content/uploads/2018/06/word-image-270.png 551w, /wp-content/uploads/2018/06/word-image-270-300x36.png 300w" sizes="(max-width: 551px) 100vw, 551px" /></p>
<p>&lt;script&gt;</p>
<p>var cookie = document.cookie</p>
<p>//发送一个jsonp请求</p>
<p>&lt;/script&gt;</p>
<p>访问此标题的时候就会弹出1，从而达成攻击；</p>
<p><img loading="lazy" decoding="async" width="423" height="122" class="wp-image-7667" src="/wp-content/uploads/2018/06/word-image-271.png" srcset="/wp-content/uploads/2018/06/word-image-271.png 423w, /wp-content/uploads/2018/06/word-image-271-300x87.png 300w" sizes="(max-width: 423px) 100vw, 423px" /></p>
<h2>防止xss攻击（防止js攻击）</h2>
<h3>使用htmlspecialchars函数防止</h3>
<p>注： 百度富文本编辑器ueditor自动将危险的代码如js进行转化为实体符号。</p>
<p>htmlspecialchars函数的作用：将html标签符号转化为实体符号。</p>
<p>如：大于号“&gt;”会被转化为 “&amp;gt;”</p>
<p>如：大于号“&lt;”会被转化为 “&amp;lt;”</p>
<p>可以在配置文件config,添加全局的过滤函数：</p>
<p><img loading="lazy" decoding="async" width="933" height="232" class="wp-image-7668" src="/wp-content/uploads/2018/06/word-image-272.png" srcset="/wp-content/uploads/2018/06/word-image-272.png 933w, /wp-content/uploads/2018/06/word-image-272-300x75.png 300w, /wp-content/uploads/2018/06/word-image-272-768x191.png 768w" sizes="(max-width: 933px) 100vw, 933px" /></p>
<p>此种缺点：会把html和js代码的特殊符号都进行转移，不满足我们的要求。我们只需要转移js代码。如下所示：</p>
<p><img loading="lazy" decoding="async" width="1068" height="134" class="wp-image-7669" src="/wp-content/uploads/2018/06/word-image-273.png" srcset="/wp-content/uploads/2018/06/word-image-273.png 1068w, /wp-content/uploads/2018/06/word-image-273-300x38.png 300w, /wp-content/uploads/2018/06/word-image-273-768x96.png 768w, /wp-content/uploads/2018/06/word-image-273-1024x128.png 1024w" sizes="(max-width: 1068px) 100vw, 1068px" /></p>
<p>解决办法：</p>
<ol>
<li>不使用函数htmlspecialchars()进行处理，但可能会出现xss攻击。</li>
<li>使用htmlspecialchars()函数处理，页面的数据（富文本html）又不能正常显示出来，可以借助htmlspecialchars_decode()反转，把html实体符号转化为html标签，但这又可能会造成xss攻击。</li>
</ol>
<p>我们的希望是HTML可以正常显示，但是又不希望js代码被执行。</p>
<p>这时可以借助第三方防止xss攻击的插件如：HTMLPurifier，此插件会把浏览器提交过来的数据有选择性的过滤。只过滤危险的js代码，保留html代码，这就刚好满足我们的需求。</p>
<h3>使用插件HTMLPurifier防止</h3>
<p>复制防止xss攻击的库到项目extend目录中。</p>
<p><img loading="lazy" decoding="async" width="965" height="325" class="wp-image-7670" src="/wp-content/uploads/2018/06/word-image-274.png" srcset="/wp-content/uploads/2018/06/word-image-274.png 965w, /wp-content/uploads/2018/06/word-image-274-300x101.png 300w, /wp-content/uploads/2018/06/word-image-274-768x259.png 768w" sizes="(max-width: 965px) 100vw, 965px" /></p>
<p>把HTMLPurifier中的example.php文件中函数定义在common.php中，并且修改路径</p>
<p><img loading="lazy" decoding="async" width="966" height="455" class="wp-image-7671" src="/wp-content/uploads/2018/06/word-image-275.png" srcset="/wp-content/uploads/2018/06/word-image-275.png 966w, /wp-content/uploads/2018/06/word-image-275-300x141.png 300w, /wp-content/uploads/2018/06/word-image-275-768x362.png 768w" sizes="(max-width: 966px) 100vw, 966px" /></p>
<p>需要把函数名为removeXSS设置为tp的全局的默认过滤函数</p>
<p><img loading="lazy" decoding="async" width="928" height="290" class="wp-image-7672" src="/wp-content/uploads/2018/06/word-image-276.png" srcset="/wp-content/uploads/2018/06/word-image-276.png 928w, /wp-content/uploads/2018/06/word-image-276-300x94.png 300w, /wp-content/uploads/2018/06/word-image-276-768x240.png 768w" sizes="(max-width: 928px) 100vw, 928px" /></p>
<p>使用之后，只会把js代码进行过滤，保留html代码：</p>
<p><img loading="lazy" decoding="async" width="1001" height="163" class="wp-image-7673" src="/wp-content/uploads/2018/06/word-image-277.png" srcset="/wp-content/uploads/2018/06/word-image-277.png 1001w, /wp-content/uploads/2018/06/word-image-277-300x49.png 300w, /wp-content/uploads/2018/06/word-image-277-768x125.png 768w" sizes="(max-width: 1001px) 100vw, 1001px" /></p>
<p>显示就不会造成攻击，html正常显示：</p>
<p><img loading="lazy" decoding="async" width="913" height="159" class="wp-image-7674" src="/wp-content/uploads/2018/06/word-image-278.png" srcset="/wp-content/uploads/2018/06/word-image-278.png 913w, /wp-content/uploads/2018/06/word-image-278-300x52.png 300w, /wp-content/uploads/2018/06/word-image-278-768x134.png 768w" sizes="(max-width: 913px) 100vw, 913px" /></p>
<h1>扩展-验证插件jquery-validate的使用</h1>
<p>前端验证目的：减轻服务器压力，提高用户体验。</p>
<p>后端验证：主要保证数据的安全（不要信任浏览器携带过来的任何数据）</p>
<p>具体使用：<a href="/goto/6kfy" rel="nofollow">https://www.jianshu.com/p/e1d5f0dc2f5d</a></p>
<p>手册：</p>
<p><img loading="lazy" decoding="async" width="261" height="25" class="wp-image-7675" src="/wp-content/uploads/2018/06/word-image-279.png" /></p>
<h1>模型的事件（钩子）</h1>
<p>所谓的事件就类似于svn中的钩子一样，做一件事情都有前事件和后事情发生。</p>
<p>给表tp_category添加一个zhujian字段，目的是记录当前记录的主键值。</p>
<p><img loading="lazy" decoding="async" width="637" height="223" class="wp-image-7676" src="/wp-content/uploads/2018/06/word-image-280.png" srcset="/wp-content/uploads/2018/06/word-image-280.png 637w, /wp-content/uploads/2018/06/word-image-280-300x105.png 300w" sizes="(max-width: 637px) 100vw, 637px" /></p>
<p>让zhujian字段和cat_id的值保持一致，我们一把入库成功后要更新:</p>
<p>常规做法如下：</p>
<p><img loading="lazy" decoding="async" width="770" height="139" class="wp-image-7677" src="/wp-content/uploads/2018/06/word-image-281.png" srcset="/wp-content/uploads/2018/06/word-image-281.png 770w, /wp-content/uploads/2018/06/word-image-281-300x54.png 300w, /wp-content/uploads/2018/06/word-image-281-768x139.png 768w" sizes="(max-width: 770px) 100vw, 770px" /></p>
<p>但是不建议上面写，我们希望只把业务逻辑写在控制器，我们把数据有关的操作写在模型的事件中。</p>
<p>模型中注册事件：</p>
<p><img loading="lazy" decoding="async" width="993" height="349" class="wp-image-7678" src="/wp-content/uploads/2018/06/word-image-282.png" srcset="/wp-content/uploads/2018/06/word-image-282.png 993w, /wp-content/uploads/2018/06/word-image-282-300x105.png 300w, /wp-content/uploads/2018/06/word-image-282-768x270.png 768w" sizes="(max-width: 993px) 100vw, 993px" /></p>
<p>我们可以在模型中注册after_insert事件，即入库成功之后，把zhujian的字段和cat_id的保持一致。</p>
<p><img loading="lazy" decoding="async" width="1076" height="562" class="wp-image-7679" src="/wp-content/uploads/2018/06/word-image-283.png" srcset="/wp-content/uploads/2018/06/word-image-283.png 1076w, /wp-content/uploads/2018/06/word-image-283-300x157.png 300w, /wp-content/uploads/2018/06/word-image-283-768x401.png 768w, /wp-content/uploads/2018/06/word-image-283-1024x535.png 1024w" sizes="(max-width: 1076px) 100vw, 1076px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="698" height="34" class="wp-image-7680" src="/wp-content/uploads/2018/06/word-image-284.png" srcset="/wp-content/uploads/2018/06/word-image-284.png 698w, /wp-content/uploads/2018/06/word-image-284-300x15.png 300w" sizes="(max-width: 698px) 100vw, 698px" /></p>
<p>触发事件的流程：入库前事件&#8212;&gt;save()&#8212;-&gt;入库后的事件，</p>
<p>如果在入库前事件前返回false,则事件不会继续执行。</p>
<p><img loading="lazy" decoding="async" width="995" height="443" class="wp-image-7681" src="/wp-content/uploads/2018/06/word-image-285.png" srcset="/wp-content/uploads/2018/06/word-image-285.png 995w, /wp-content/uploads/2018/06/word-image-285-300x134.png 300w, /wp-content/uploads/2018/06/word-image-285-768x342.png 768w" sizes="(max-width: 995px) 100vw, 995px" /></p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7628.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5 商城（一）环境部署、数据表、后台首页、用户 CURD、Ajax 状态切换、后台登录、后台退出、后台防翻墙、RBAC</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7682.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7682.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:40:08 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[TP5.0商城]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[Ajax 状态切换]]></category>
		<category><![CDATA[RBAC]]></category>
		<category><![CDATA[后台登录]]></category>
		<category><![CDATA[后台退出]]></category>
		<category><![CDATA[后台防翻墙]]></category>
		<category><![CDATA[后台首页]]></category>
		<category><![CDATA[数据表]]></category>
		<category><![CDATA[环境部署]]></category>
		<category><![CDATA[用户 CURD]]></category>
		<guid isPermaLink="false">/?p=7682</guid>

					<description><![CDATA[商城实战第一天 电商介绍 电子商务模式介绍 现在的电子商务平台主要分为以下几种类型： B2C ：全称-Busi [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>商城实战第一天</h1>
<h1>电商介绍</h1>
<h2>电子商务模式介绍</h2>
<p>现在的电子商务平台主要分为以下几种类型：</p>
<ul>
<li>B2C ：全称-Business to Consumer , 即企业与消费者之间的电子商务。</li>
</ul>
<p>常见的有B2C网站有：天猫（商家入驻（实体店,保证金20W），需要营业许可证等资料）、京东(商家也可入驻)、当当网、唯品会、凡客、小米、华为、oppo等</p>
<ul>
<li>C2C: 全称-Consumer to Consumer，即消费者与消费者之间的电子商务。</li>
</ul>
<p>典型的C2C网站就是国内的淘宝（需要交保证金2000元左右），还有58同城，二手交易网站如：闲鱼二手交易网。</p>
<ul>
<li>O2O: 全称-Online to Offline,线上与线下相结合的电子商务。</li>
</ul>
<p>常见的有：苏宁、美团、国美、滴滴打车等。</p>
<ul>
<li>B2B：全称-Business to Business 即企业与企业之间的电子商务。（阿里妈妈）</li>
</ul>
<h2>常见的开源商城</h2>
<h3>（1）Ecshop</h3>
<p>ECShop是一款B2C独立网店系统，适合企业及个人快速构建个性化网上商店。系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序。</p>
<p>网址：<a href="/goto/c9pa" rel="nofollow">http://www.ecshop.com/</a></p>
<p><img loading="lazy" decoding="async" width="1105" height="498" class="wp-image-7684" src="/wp-content/uploads/2018/06/word-image-286.png" srcset="/wp-content/uploads/2018/06/word-image-286.png 1105w, /wp-content/uploads/2018/06/word-image-286-300x135.png 300w, /wp-content/uploads/2018/06/word-image-286-768x346.png 768w, /wp-content/uploads/2018/06/word-image-286-1024x461.png 1024w" sizes="(max-width: 1105px) 100vw, 1105px" /></p>
<p>特点：开源、免费(个人学习使用没有任何问题)。但是企业使用用来盈利的话需要一定的授权费用（3000元左右）。</p>
<h3>（2）shopex</h3>
<p>网址：<a href="/goto/zptp" rel="nofollow">http://www.shopex.cn/</a></p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" width="1087" height="468" class="wp-image-7685" src="/wp-content/uploads/2018/06/word-image-287.png" srcset="/wp-content/uploads/2018/06/word-image-287.png 1087w, /wp-content/uploads/2018/06/word-image-287-300x129.png 300w, /wp-content/uploads/2018/06/word-image-287-768x331.png 768w, /wp-content/uploads/2018/06/word-image-287-1024x441.png 1024w" sizes="(max-width: 1087px) 100vw, 1087px" /></p>
<p>特点：商业版，代码是加密过的。</p>
<h3>（3）shopnc</h3>
<p>网址: <a href="/goto/ajli" rel="nofollow">http://www.shopnc.net/</a></p>
<p>演示地址： <a href="/goto/ubug" rel="nofollow">http://b2b2c.shopnctest.com/dema/shop/index.php</a></p>
<p><img loading="lazy" decoding="async" width="1104" height="416" class="wp-image-7686" src="/wp-content/uploads/2018/06/word-image-288.png" srcset="/wp-content/uploads/2018/06/word-image-288.png 1104w, /wp-content/uploads/2018/06/word-image-288-300x113.png 300w, /wp-content/uploads/2018/06/word-image-288-768x289.png 768w, /wp-content/uploads/2018/06/word-image-288-1024x386.png 1024w" sizes="(max-width: 1104px) 100vw, 1104px" /></p>
<p>特点：不开源、不免费</p>
<p>小结：</p>
<p>开源不代表免费，可以自己学习研究使用，但是以盈利为目的使用需要交一定的授权费用。</p>
<h2>安装Ecshop开源商城</h2>
<p>现在的Ecshop主要有以下两个版本：</p>
<ul>
<li>3.0版本：需要php5.4版本以上</li>
<li>2.7版本：需要在php5.3以下（如：phpstudy集成环境进行php降级），当然5.4、5、5版本也是可以的，只是需要修改部分代码。</li>
</ul>
<p>这里建议安装Ecshop的兼容版本，已经兼容各个php版本。</p>
<p><img loading="lazy" decoding="async" width="246" height="27" class="wp-image-7687" src="/wp-content/uploads/2018/06/word-image-289.png" /></p>
<h3>域名部署访问 ecshop</h3>
<p>一般把第三方开源项目部署在自己的机子上面域名前建议加个vendor,如：vendor.shop.com。明确知道这个程序是第三方程序。本地自己开发的项目话建议使用local进行开头，如:local.shop.com。</p>
<p>步骤1：把ecshop开源程序的所有的文件复制到我们的项目目录</p>
<p><img loading="lazy" decoding="async" width="841" height="424" class="wp-image-7688" src="/wp-content/uploads/2018/06/word-image-290.png" srcset="/wp-content/uploads/2018/06/word-image-290.png 841w, /wp-content/uploads/2018/06/word-image-290-300x151.png 300w, /wp-content/uploads/2018/06/word-image-290-768x387.png 768w" sizes="(max-width: 841px) 100vw, 841px" /></p>
<p>步骤2：配置虚拟主机，如域名为上面的vendor.ecshop.com</p>
<ol>
<li>phpstudy设置虚拟主机</li>
<li>设置host文件映射</li>
<li>重启phpstudy</li>
</ol>
<p>步骤3：输入域名进行安装配置</p>
<ol>
<li>勾选</li>
</ol>
<p><img loading="lazy" decoding="async" width="1088" height="661" class="wp-image-7689" src="/wp-content/uploads/2018/06/word-image-291.png" srcset="/wp-content/uploads/2018/06/word-image-291.png 1088w, /wp-content/uploads/2018/06/word-image-291-300x182.png 300w, /wp-content/uploads/2018/06/word-image-291-768x467.png 768w, /wp-content/uploads/2018/06/word-image-291-1024x622.png 1024w" sizes="(max-width: 1088px) 100vw, 1088px" /></p>
<p>b、配置系统</p>
<p><img loading="lazy" decoding="async" width="861" height="267" class="wp-image-7690" src="/wp-content/uploads/2018/06/word-image-292.png" srcset="/wp-content/uploads/2018/06/word-image-292.png 861w, /wp-content/uploads/2018/06/word-image-292-300x93.png 300w, /wp-content/uploads/2018/06/word-image-292-768x238.png 768w" sizes="(max-width: 861px) 100vw, 861px" /></p>
<p>c、配置数据库的信息</p>
<p><img loading="lazy" decoding="async" width="777" height="650" class="wp-image-7691" src="/wp-content/uploads/2018/06/word-image-293.png" srcset="/wp-content/uploads/2018/06/word-image-293.png 777w, /wp-content/uploads/2018/06/word-image-293-300x251.png 300w, /wp-content/uploads/2018/06/word-image-293-768x642.png 768w" sizes="(max-width: 777px) 100vw, 777px" /> <img loading="lazy" decoding="async" width="834" height="242" class="wp-image-7692" src="/wp-content/uploads/2018/06/word-image-294.png" srcset="/wp-content/uploads/2018/06/word-image-294.png 834w, /wp-content/uploads/2018/06/word-image-294-300x87.png 300w, /wp-content/uploads/2018/06/word-image-294-768x223.png 768w" sizes="(max-width: 834px) 100vw, 834px" /></p>
<p>访问ecshop前台：<a href="/goto/z1k0" rel="nofollow">http:/域名/</a></p>
<p>访问ecshop后台：<a href="/goto/1knx" rel="nofollow">http:/域名/admin/</a></p>
<p><img loading="lazy" decoding="async" width="781" height="382" class="wp-image-7693" src="/wp-content/uploads/2018/06/word-image-295.png" srcset="/wp-content/uploads/2018/06/word-image-295.png 781w, /wp-content/uploads/2018/06/word-image-295-300x147.png 300w, /wp-content/uploads/2018/06/word-image-295-768x376.png 768w" sizes="(max-width: 781px) 100vw, 781px" /></p>
<h1>部署tp5商城项目环境</h1>
<h2>部署虚拟主机</h2>
<p>三步：</p>
<p>步骤1：把tp5项目程序复制指定虚拟目录</p>
<p>步骤2：使用phpstudy配置域名如为：<a href="/goto/x9uh" rel="nofollow">www.php15shop.com</a>，虚拟目录需要绑定到public目录下面</p>
<p>步骤3：设置hosts文件映射</p>
<p>最后访问如下，说明配置成功：</p>
<p><img loading="lazy" decoding="async" width="693" height="379" class="wp-image-7694" src="/wp-content/uploads/2018/06/word-image-296.png" srcset="/wp-content/uploads/2018/06/word-image-296.png 693w, /wp-content/uploads/2018/06/word-image-296-300x164.png 300w" sizes="(max-width: 693px) 100vw, 693px" /></p>
<h2>导入商城项目所有数据表</h2>
<p>建议使用navicat可视化工具进行完成，找到对应的sql文件，进行导入。</p>
<p>要先创建一个数据库，如php15shop</p>
<p><img loading="lazy" decoding="async" width="736" height="210" class="wp-image-7695" src="/wp-content/uploads/2018/06/word-image-297.png" srcset="/wp-content/uploads/2018/06/word-image-297.png 736w, /wp-content/uploads/2018/06/word-image-297-300x86.png 300w" sizes="(max-width: 736px) 100vw, 736px" /></p>
<p>&nbsp;</p>
<p>每张表的字段信息可以参考数据库文档：</p>
<p><img loading="lazy" decoding="async" width="652" height="66" class="wp-image-7696" src="/wp-content/uploads/2018/06/word-image-298.png" srcset="/wp-content/uploads/2018/06/word-image-298.png 652w, /wp-content/uploads/2018/06/word-image-298-300x30.png 300w" sizes="(max-width: 652px) 100vw, 652px" /></p>
<h2>项目前的一些配置</h2>
<p>我们可以先把数据库、控制器后缀、静态资源目录等一些基本配置先定义好。</p>
<ul>
<li>数据库配置</li>
</ul>
<p><img loading="lazy" decoding="async" width="935" height="629" class="wp-image-7697" src="/wp-content/uploads/2018/06/word-image-299.png" srcset="/wp-content/uploads/2018/06/word-image-299.png 935w, /wp-content/uploads/2018/06/word-image-299-300x202.png 300w, /wp-content/uploads/2018/06/word-image-299-768x517.png 768w" sizes="(max-width: 935px) 100vw, 935px" /></p>
<ul>
<li>控制器后缀</li>
</ul>
<p><img loading="lazy" decoding="async" width="798" height="303" class="wp-image-7698" src="/wp-content/uploads/2018/06/word-image-300.png" srcset="/wp-content/uploads/2018/06/word-image-300.png 798w, /wp-content/uploads/2018/06/word-image-300-300x114.png 300w, /wp-content/uploads/2018/06/word-image-300-768x292.png 768w" sizes="(max-width: 798px) 100vw, 798px" /></p>
<ul>
<li>配置静态资源路径，把后台静态资源放到相应的目录,配置后台密码加密验salt</li>
</ul>
<p><img loading="lazy" decoding="async" width="767" height="329" class="wp-image-7699" src="/wp-content/uploads/2018/06/word-image-301.png" srcset="/wp-content/uploads/2018/06/word-image-301.png 767w, /wp-content/uploads/2018/06/word-image-301-300x129.png 300w" sizes="(max-width: 767px) 100vw, 767px" /></p>
<ul>
<li>先设置默认模块为admin、开发前台时（项目上线）设置为home</li>
</ul>
<p><img loading="lazy" decoding="async" width="785" height="161" class="wp-image-7700" src="/wp-content/uploads/2018/06/word-image-302.png" srcset="/wp-content/uploads/2018/06/word-image-302.png 785w, /wp-content/uploads/2018/06/word-image-302-300x62.png 300w, /wp-content/uploads/2018/06/word-image-302-768x158.png 768w" sizes="(max-width: 785px) 100vw, 785px" /></p>
<ul>
<li>并且开启调试模式,页面trace调试，看到错误的详细信息</li>
</ul>
<p><img loading="lazy" decoding="async" width="866" height="277" class="wp-image-7701" src="/wp-content/uploads/2018/06/word-image-303.png" srcset="/wp-content/uploads/2018/06/word-image-303.png 866w, /wp-content/uploads/2018/06/word-image-303-300x96.png 300w, /wp-content/uploads/2018/06/word-image-303-768x246.png 768w" sizes="(max-width: 866px) 100vw, 866px" /></p>
<p>开启页面trace调试，页面右下角多处一个图标。</p>
<p><img loading="lazy" decoding="async" width="153" height="49" class="wp-image-7702" src="/wp-content/uploads/2018/06/word-image-304.png" srcset="/wp-content/uploads/2018/06/word-image-304.png 153w, /wp-content/uploads/2018/06/word-image-304-150x49.png 150w" sizes="(max-width: 153px) 100vw, 153px" /></p>
<ul>
<li>开启模型获取数据返回关联数组的配置</li>
</ul>
<p><img loading="lazy" decoding="async" width="901" height="177" class="wp-image-7703" src="/wp-content/uploads/2018/06/word-image-305.png" srcset="/wp-content/uploads/2018/06/word-image-305.png 901w, /wp-content/uploads/2018/06/word-image-305-300x59.png 300w, /wp-content/uploads/2018/06/word-image-305-768x151.png 768w" sizes="(max-width: 901px) 100vw, 901px" /></p>
<ul>
<li>修改重写文件.htaccess隐藏单一入口文件访问</li>
</ul>
<p>这里需要在httpd.conf开启rewrite重写模块，和在虚拟主机中把 AllowOverride None改为 AllowOverride All，这两步在安装phpstudy的时候和配置虚拟主机时其已经帮我们设置好了。</p>
<p>只需要改修改重写文件.htaccess，前面加个问号?</p>
<h1>三、搭建后台首页</h1>
<p><img loading="lazy" decoding="async" width="844" height="270" class="wp-image-7704" src="/wp-content/uploads/2018/06/word-image-306.png" srcset="/wp-content/uploads/2018/06/word-image-306.png 844w, /wp-content/uploads/2018/06/word-image-306-300x96.png 300w, /wp-content/uploads/2018/06/word-image-306-768x246.png 768w" sizes="(max-width: 844px) 100vw, 844px" /></p>
<p>步骤1：在后台admin建立一个index控制器，分别建立top、main、left、index</p>
<p><img loading="lazy" decoding="async" width="774" height="613" class="wp-image-7705" src="/wp-content/uploads/2018/06/word-image-307.png" srcset="/wp-content/uploads/2018/06/word-image-307.png 774w, /wp-content/uploads/2018/06/word-image-307-300x238.png 300w, /wp-content/uploads/2018/06/word-image-307-768x608.png 768w" sizes="(max-width: 774px) 100vw, 774px" /></p>
<p>步骤2：复制后台指定的模板到指定的目录，并且修改每个模板的静态资源路径</p>
<p><img loading="lazy" decoding="async" width="1264" height="457" class="wp-image-7706" src="/wp-content/uploads/2018/06/word-image-308.png" srcset="/wp-content/uploads/2018/06/word-image-308.png 1264w, /wp-content/uploads/2018/06/word-image-308-300x108.png 300w, /wp-content/uploads/2018/06/word-image-308-768x278.png 768w, /wp-content/uploads/2018/06/word-image-308-1024x370.png 1024w" sizes="(max-width: 1264px) 100vw, 1264px" /></p>
<p>访问效果：</p>
<p><img loading="lazy" decoding="async" width="744" height="432" class="wp-image-7707" src="/wp-content/uploads/2018/06/word-image-309.png" srcset="/wp-content/uploads/2018/06/word-image-309.png 744w, /wp-content/uploads/2018/06/word-image-309-300x174.png 300w" sizes="(max-width: 744px) 100vw, 744px" /></p>
<h1>四、用户表的CURD操作</h1>
<h3>完成用户的添加功能</h3>
<p>步骤1：在后台创建User控制器，并建立一个add方法输出模板内容</p>
<p><img loading="lazy" decoding="async" width="794" height="286" class="wp-image-7708" src="/wp-content/uploads/2018/06/word-image-310.png" srcset="/wp-content/uploads/2018/06/word-image-310.png 794w, /wp-content/uploads/2018/06/word-image-310-300x108.png 300w, /wp-content/uploads/2018/06/word-image-310-768x277.png 768w" sizes="(max-width: 794px) 100vw, 794px" /></p>
<p>步骤2：修改add.html模板的name名称</p>
<p><img loading="lazy" decoding="async" width="1286" height="622" class="wp-image-7709" src="/wp-content/uploads/2018/06/word-image-311.png" srcset="/wp-content/uploads/2018/06/word-image-311.png 1286w, /wp-content/uploads/2018/06/word-image-311-300x145.png 300w, /wp-content/uploads/2018/06/word-image-311-768x371.png 768w, /wp-content/uploads/2018/06/word-image-311-1024x495.png 1024w" sizes="(max-width: 1286px) 100vw, 1286px" /></p>
<p>步骤3：定义当前表的验证器</p>
<p><img loading="lazy" decoding="async" width="1209" height="714" class="wp-image-7710" src="/wp-content/uploads/2018/06/word-image-312.png" srcset="/wp-content/uploads/2018/06/word-image-312.png 1209w, /wp-content/uploads/2018/06/word-image-312-300x177.png 300w, /wp-content/uploads/2018/06/word-image-312-768x454.png 768w, /wp-content/uploads/2018/06/word-image-312-1024x605.png 1024w" sizes="(max-width: 1209px) 100vw, 1209px" /></p>
<p>步骤4：在模型中定义前入库的钩子事件，完成密码字段的加密</p>
<p><img loading="lazy" decoding="async" width="1101" height="436" class="wp-image-7711" src="/wp-content/uploads/2018/06/word-image-313.png" srcset="/wp-content/uploads/2018/06/word-image-313.png 1101w, /wp-content/uploads/2018/06/word-image-313-300x119.png 300w, /wp-content/uploads/2018/06/word-image-313-768x304.png 768w, /wp-content/uploads/2018/06/word-image-313-1024x406.png 1024w" sizes="(max-width: 1101px) 100vw, 1101px" /></p>
<p>步骤5：控制器完成验证入库操作</p>
<p><img loading="lazy" decoding="async" width="1191" height="699" class="wp-image-7712" src="/wp-content/uploads/2018/06/word-image-314.png" srcset="/wp-content/uploads/2018/06/word-image-314.png 1191w, /wp-content/uploads/2018/06/word-image-314-300x176.png 300w, /wp-content/uploads/2018/06/word-image-314-768x451.png 768w, /wp-content/uploads/2018/06/word-image-314-1024x601.png 1024w" sizes="(max-width: 1191px) 100vw, 1191px" /></p>
<h3>完成用户列表功能及分页</h3>
<p>步骤1：在后台User控制器建立一个index方法，取出所有的用户数据，并分配到模板中</p>
<p><img loading="lazy" decoding="async" width="831" height="395" class="wp-image-7713" src="/wp-content/uploads/2018/06/word-image-315.png" srcset="/wp-content/uploads/2018/06/word-image-315.png 831w, /wp-content/uploads/2018/06/word-image-315-300x143.png 300w, /wp-content/uploads/2018/06/word-image-315-768x365.png 768w" sizes="(max-width: 831px) 100vw, 831px" /></p>
<p>步骤2：模板遍历数据</p>
<p><img loading="lazy" decoding="async" width="1039" height="601" class="wp-image-7714" src="/wp-content/uploads/2018/06/word-image-316.png" srcset="/wp-content/uploads/2018/06/word-image-316.png 1039w, /wp-content/uploads/2018/06/word-image-316-300x174.png 300w, /wp-content/uploads/2018/06/word-image-316-768x444.png 768w, /wp-content/uploads/2018/06/word-image-316-1024x592.png 1024w" sizes="(max-width: 1039px) 100vw, 1039px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="941" height="192" class="wp-image-7715" src="/wp-content/uploads/2018/06/word-image-317.png" srcset="/wp-content/uploads/2018/06/word-image-317.png 941w, /wp-content/uploads/2018/06/word-image-317-300x61.png 300w, /wp-content/uploads/2018/06/word-image-317-768x157.png 768w" sizes="(max-width: 941px) 100vw, 941px" /></p>
<h3>完成用户的编辑功能</h3>
<p>编辑用户的时候，密码选项需要考虑两种情况：</p>
<p>①如密码和确认密码都为空，说明用户不想修改密码，则保留原来的密码。</p>
<p>②如果两个密码有一个不为空，说明用户想修改密码，则必须要求用户两次密码一致。</p>
<p>代码如下：</p>
<p>步骤1：给编辑的设置一个链接地址，携带一个主键值</p>
<p><img loading="lazy" decoding="async" width="1260" height="305" class="wp-image-7716" src="/wp-content/uploads/2018/06/word-image-318.png" srcset="/wp-content/uploads/2018/06/word-image-318.png 1260w, /wp-content/uploads/2018/06/word-image-318-300x73.png 300w, /wp-content/uploads/2018/06/word-image-318-768x186.png 768w, /wp-content/uploads/2018/06/word-image-318-1024x248.png 1024w" sizes="(max-width: 1260px) 100vw, 1260px" /></p>
<p>步骤2：使用jquery-validate对密码字段进行验证</p>
<p><img loading="lazy" decoding="async" width="1008" height="318" class="wp-image-7717" src="/wp-content/uploads/2018/06/word-image-319.png" srcset="/wp-content/uploads/2018/06/word-image-319.png 1008w, /wp-content/uploads/2018/06/word-image-319-300x95.png 300w, /wp-content/uploads/2018/06/word-image-319-768x242.png 768w" sizes="(max-width: 1008px) 100vw, 1008px" /></p>
<p>规则如下：</p>
<p><img loading="lazy" decoding="async" width="841" height="711" class="wp-image-7718" src="/wp-content/uploads/2018/06/word-image-320.png" srcset="/wp-content/uploads/2018/06/word-image-320.png 841w, /wp-content/uploads/2018/06/word-image-320-300x254.png 300w, /wp-content/uploads/2018/06/word-image-320-768x649.png 768w" sizes="(max-width: 841px) 100vw, 841px" /> <img loading="lazy" decoding="async" width="590" height="144" class="wp-image-7719" src="/wp-content/uploads/2018/06/word-image-321.png" srcset="/wp-content/uploads/2018/06/word-image-321.png 590w, /wp-content/uploads/2018/06/word-image-321-300x73.png 300w" sizes="(max-width: 590px) 100vw, 590px" /></p>
<p>注：要修改style.css文件样式，因为有样式冲突</p>
<p><img loading="lazy" decoding="async" width="1138" height="179" class="wp-image-7720" src="/wp-content/uploads/2018/06/word-image-322.png" srcset="/wp-content/uploads/2018/06/word-image-322.png 1138w, /wp-content/uploads/2018/06/word-image-322-300x47.png 300w, /wp-content/uploads/2018/06/word-image-322-768x121.png 768w, /wp-content/uploads/2018/06/word-image-322-1024x161.png 1024w" sizes="(max-width: 1138px) 100vw, 1138px" /></p>
<p>设置upd.html模板内容回显数据：</p>
<p><img loading="lazy" decoding="async" width="1270" height="671" class="wp-image-7721" src="/wp-content/uploads/2018/06/word-image-323.png" srcset="/wp-content/uploads/2018/06/word-image-323.png 1270w, /wp-content/uploads/2018/06/word-image-323-300x159.png 300w, /wp-content/uploads/2018/06/word-image-323-768x406.png 768w, /wp-content/uploads/2018/06/word-image-323-1024x541.png 1024w" sizes="(max-width: 1270px) 100vw, 1270px" /></p>
<p>步骤3：upd方法中完成编辑的验证编辑入库</p>
<p><img loading="lazy" decoding="async" width="1160" height="520" class="wp-image-7722" src="/wp-content/uploads/2018/06/word-image-324.png" srcset="/wp-content/uploads/2018/06/word-image-324.png 1160w, /wp-content/uploads/2018/06/word-image-324-300x134.png 300w, /wp-content/uploads/2018/06/word-image-324-768x344.png 768w, /wp-content/uploads/2018/06/word-image-324-1024x459.png 1024w" sizes="(max-width: 1160px) 100vw, 1160px" /></p>
<p>同时修改编辑场景的验证器：</p>
<p><img loading="lazy" decoding="async" width="1002" height="485" class="wp-image-7723" src="/wp-content/uploads/2018/06/word-image-325.png" srcset="/wp-content/uploads/2018/06/word-image-325.png 1002w, /wp-content/uploads/2018/06/word-image-325-300x145.png 300w, /wp-content/uploads/2018/06/word-image-325-768x372.png 768w" sizes="(max-width: 1002px) 100vw, 1002px" /></p>
<h3>ajax控制用户的登录状态</h3>
<p>步骤1：先给标签加一个a标签，并且阻止默认行为，同时加一个is_active和user_id属性，目的是获取当前记录的状态值和主键值，并且绑定类名为changeActive。</p>
<p><img loading="lazy" decoding="async" width="1197" height="259" class="wp-image-7724" src="/wp-content/uploads/2018/06/word-image-326.png" srcset="/wp-content/uploads/2018/06/word-image-326.png 1197w, /wp-content/uploads/2018/06/word-image-326-300x65.png 300w, /wp-content/uploads/2018/06/word-image-326-768x166.png 768w, /wp-content/uploads/2018/06/word-image-326-1024x222.png 1024w" sizes="(max-width: 1197px) 100vw, 1197px" /></p>
<p>步骤2：给class=changeActive 绑定单击事件，发送ajax请求</p>
<p><img loading="lazy" decoding="async" width="1244" height="493" class="wp-image-7725" src="/wp-content/uploads/2018/06/word-image-327.png" srcset="/wp-content/uploads/2018/06/word-image-327.png 1244w, /wp-content/uploads/2018/06/word-image-327-300x119.png 300w, /wp-content/uploads/2018/06/word-image-327-768x304.png 768w, /wp-content/uploads/2018/06/word-image-327-1024x406.png 1024w" sizes="(max-width: 1244px) 100vw, 1244px" /></p>
<p>步骤3：在User控制器建立一个ajaxChangeActive方法，完成状态的更改</p>
<p><img loading="lazy" decoding="async" width="831" height="646" class="wp-image-7726" src="/wp-content/uploads/2018/06/word-image-328.png" srcset="/wp-content/uploads/2018/06/word-image-328.png 831w, /wp-content/uploads/2018/06/word-image-328-300x233.png 300w, /wp-content/uploads/2018/06/word-image-328-768x597.png 768w" sizes="(max-width: 831px) 100vw, 831px" /></p>
<p>注意：由于更改状态值的时候会触发编辑的前钩子，这时候没有携带密码字段前钩子会直接报错，解决办法：对前钩子有没有密码字段进行isset判断即可:</p>
<p><img loading="lazy" decoding="async" width="971" height="482" class="wp-image-7727" src="/wp-content/uploads/2018/06/word-image-329.png" srcset="/wp-content/uploads/2018/06/word-image-329.png 971w, /wp-content/uploads/2018/06/word-image-329-300x149.png 300w, /wp-content/uploads/2018/06/word-image-329-768x381.png 768w" sizes="(max-width: 971px) 100vw, 971px" /></p>
<p>提示：调试ajax的时候，务必要打开控制器network进行调试。可以打开response选项看报啥错，这样可以快速定位到错误的原因。</p>
<h1>五、完成后台用户登录|退出|防翻墙功能</h1>
<h2>完成后台登录功能</h2>
<p>步骤1：在后台建立一个Public控制器，并建立一个login方法，输出登录模板同时，同时完成登录的功能实现</p>
<p><img loading="lazy" decoding="async" width="1135" height="651" class="wp-image-7728" src="/wp-content/uploads/2018/06/word-image-330.png" srcset="/wp-content/uploads/2018/06/word-image-330.png 1135w, /wp-content/uploads/2018/06/word-image-330-300x172.png 300w, /wp-content/uploads/2018/06/word-image-330-768x441.png 768w, /wp-content/uploads/2018/06/word-image-330-1024x587.png 1024w" sizes="(max-width: 1135px) 100vw, 1135px" /></p>
<p>同时在User模型中，定义一个checkUser的方法，检测用户名和密码是否相等</p>
<p><img loading="lazy" decoding="async" width="1030" height="529" class="wp-image-7729" src="/wp-content/uploads/2018/06/word-image-331.png" srcset="/wp-content/uploads/2018/06/word-image-331.png 1030w, /wp-content/uploads/2018/06/word-image-331-300x154.png 300w, /wp-content/uploads/2018/06/word-image-331-768x394.png 768w, /wp-content/uploads/2018/06/word-image-331-1024x526.png 1024w" sizes="(max-width: 1030px) 100vw, 1030px" /></p>
<p>步骤2：修改login.html模板内容，显示验证码</p>
<p><img loading="lazy" decoding="async" width="1267" height="689" class="wp-image-7730" src="/wp-content/uploads/2018/06/word-image-332.png" srcset="/wp-content/uploads/2018/06/word-image-332.png 1267w, /wp-content/uploads/2018/06/word-image-332-300x163.png 300w, /wp-content/uploads/2018/06/word-image-332-768x418.png 768w, /wp-content/uploads/2018/06/word-image-332-1024x557.png 1024w" sizes="(max-width: 1267px) 100vw, 1267px" /> <img loading="lazy" decoding="async" width="1167" height="425" class="wp-image-7731" src="/wp-content/uploads/2018/06/word-image-333.png" srcset="/wp-content/uploads/2018/06/word-image-333.png 1167w, /wp-content/uploads/2018/06/word-image-333-300x109.png 300w, /wp-content/uploads/2018/06/word-image-333-768x280.png 768w, /wp-content/uploads/2018/06/word-image-333-1024x373.png 1024w" sizes="(max-width: 1167px) 100vw, 1167px" /></p>
<p>步骤3：在验证器中定义登录场景的验证规则</p>
<p><img loading="lazy" decoding="async" width="1264" height="690" class="wp-image-7732" src="/wp-content/uploads/2018/06/word-image-334.png" srcset="/wp-content/uploads/2018/06/word-image-334.png 1264w, /wp-content/uploads/2018/06/word-image-334-300x164.png 300w, /wp-content/uploads/2018/06/word-image-334-768x419.png 768w, /wp-content/uploads/2018/06/word-image-334-1024x559.png 1024w" sizes="(max-width: 1264px) 100vw, 1264px" /></p>
<p>登录成功，在top.html中回显用户名</p>
<p><img loading="lazy" decoding="async" width="1024" height="214" class="wp-image-7733" src="/wp-content/uploads/2018/06/word-image-335.png" srcset="/wp-content/uploads/2018/06/word-image-335.png 1024w, /wp-content/uploads/2018/06/word-image-335-300x63.png 300w, /wp-content/uploads/2018/06/word-image-335-768x161.png 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<h2>完成后台退出功能</h2>
<p>步骤1：在后台Public控制器建立一个logout的退出方法</p>
<p><img loading="lazy" decoding="async" width="831" height="296" class="wp-image-7734" src="/wp-content/uploads/2018/06/word-image-336.png" srcset="/wp-content/uploads/2018/06/word-image-336.png 831w, /wp-content/uploads/2018/06/word-image-336-300x107.png 300w, /wp-content/uploads/2018/06/word-image-336-768x274.png 768w" sizes="(max-width: 831px) 100vw, 831px" /></p>
<h2>防用户翻墙</h2>
<p>防翻墙思想：建立一个父控制器如：CommonController,在此控制器的构造函数中做session的判断，其他需要进行验证session的控制器就继承此公共控制器即可防止翻墙，某些控制器不需要session判断则不继承即可。（如:PublicController）</p>
<p><img loading="lazy" decoding="async" width="991" height="358" class="wp-image-7735" src="/wp-content/uploads/2018/06/word-image-337.png" srcset="/wp-content/uploads/2018/06/word-image-337.png 991w, /wp-content/uploads/2018/06/word-image-337-300x108.png 300w, /wp-content/uploads/2018/06/word-image-337-768x277.png 768w" sizes="(max-width: 991px) 100vw, 991px" /></p>
<p>其中Index 和User控制器需要继承Common，public不需要继承</p>
<p><img loading="lazy" decoding="async" width="831" height="164" class="wp-image-7736" src="/wp-content/uploads/2018/06/word-image-338.png" srcset="/wp-content/uploads/2018/06/word-image-338.png 831w, /wp-content/uploads/2018/06/word-image-338-300x59.png 300w, /wp-content/uploads/2018/06/word-image-338-768x152.png 768w" sizes="(max-width: 831px) 100vw, 831px" /> <img loading="lazy" decoding="async" width="834" height="172" class="wp-image-7737" src="/wp-content/uploads/2018/06/word-image-339.png" srcset="/wp-content/uploads/2018/06/word-image-339.png 834w, /wp-content/uploads/2018/06/word-image-339-300x62.png 300w, /wp-content/uploads/2018/06/word-image-339-768x158.png 768w" sizes="(max-width: 834px) 100vw, 834px" /></p>
<h1>六、RBAC权限控制</h1>
<h2>RBAC介绍</h2>
<p>RBAC: Role Based Access Controller ,即基于角色的访问权限控制。</p>
<p>简单的说,用户登录可以属于不同的角色，不同的角色拥有的后台访问菜单权限也不一样。</p>
<p>如：</p>
<p>如下面的每个菜单就是一个权限。</p>
<p><img loading="lazy" decoding="async" width="190" height="124" class="wp-image-7738" src="/wp-content/uploads/2018/06/word-image-340.png" /></p>
<p>后台菜单中权限一般只控制到两级权限，权限级别太深难以维护，具体要看项目需求。</p>
<p>一级权限：如：商品管理。</p>
<p>二级权限：如：商品添加、商品列表。</p>
<p>三级权限：如：商品列表中的编辑或删除操作</p>
<h2>RBAC表的表设计</h2>
<p>一般RBAC权限控制都3张表和5张表，其核心都是一样。</p>
<p>3张表：后台用户表、角色表、权限表。</p>
<p>而5张表仅把用户表和角色表、角色表和权限表其相关联的字段分别使用一个表来维护。且表多了维护起来更加繁琐。</p>
<p>这里我们采用3张表来做权限控制。</p>
<p>三张表的关系如下：</p>
<p><img loading="lazy" decoding="async" width="749" height="293" class="wp-image-7739" src="/wp-content/uploads/2018/06/word-image-341.png" srcset="/wp-content/uploads/2018/06/word-image-341.png 749w, /wp-content/uploads/2018/06/word-image-341-300x117.png 300w" sizes="(max-width: 749px) 100vw, 749px" /></p>
<p>分析：</p>
<ul>
<li>用户表通过角色字段role_id，找到与其关联的角色表role_id。</li>
<li>角色表通过所拥有的所有权限字段auth_id_list，找到与其关联的权限表的auth_id。</li>
</ul>
<p>控制权限图解：</p>
<p><img loading="lazy" decoding="async" width="1127" height="449" class="wp-image-7740" src="/wp-content/uploads/2018/06/word-image-342.png" srcset="/wp-content/uploads/2018/06/word-image-342.png 1127w, /wp-content/uploads/2018/06/word-image-342-300x120.png 300w, /wp-content/uploads/2018/06/word-image-342-768x306.png 768w, /wp-content/uploads/2018/06/word-image-342-1024x408.png 1024w" sizes="(max-width: 1127px) 100vw, 1127px" /></p>
<p>可见，一个用户对应着一个角色，一个角色可以拥有多个权限。</p>
<h1>七、RBAC功能实现</h1>
<h2>权限表的curd操作</h2>
<h3>（1）完成权限的添加</h3>
<p>步骤1：在后台建立一个Auth控制器，并建立一个add方法，输出模板内容，并完成添加权限的实现</p>
<p><img loading="lazy" decoding="async" width="1028" height="717" class="wp-image-7741" src="/wp-content/uploads/2018/06/word-image-343.png" srcset="/wp-content/uploads/2018/06/word-image-343.png 1028w, /wp-content/uploads/2018/06/word-image-343-300x209.png 300w, /wp-content/uploads/2018/06/word-image-343-768x536.png 768w, /wp-content/uploads/2018/06/word-image-343-1024x714.png 1024w" sizes="(max-width: 1028px) 100vw, 1028px" /></p>
<p>同时在Auth模型中取出权限的无限级分类数据：</p>
<p><img loading="lazy" decoding="async" width="965" height="680" class="wp-image-7742" src="/wp-content/uploads/2018/06/word-image-344.png" srcset="/wp-content/uploads/2018/06/word-image-344.png 965w, /wp-content/uploads/2018/06/word-image-344-300x211.png 300w, /wp-content/uploads/2018/06/word-image-344-768x541.png 768w" sizes="(max-width: 965px) 100vw, 965px" /></p>
<p>步骤2：设置add.html模板内容</p>
<p><img loading="lazy" decoding="async" width="1230" height="699" class="wp-image-7743" src="/wp-content/uploads/2018/06/word-image-345.png" srcset="/wp-content/uploads/2018/06/word-image-345.png 1230w, /wp-content/uploads/2018/06/word-image-345-300x170.png 300w, /wp-content/uploads/2018/06/word-image-345-768x436.png 768w, /wp-content/uploads/2018/06/word-image-345-1024x582.png 1024w" sizes="(max-width: 1230px) 100vw, 1230px" /></p>
<p>当选择顶级权限时，控制器名和方法名不可用，否则可用。因为顶级权限没有控制器名和方法名。</p>
<p><img loading="lazy" decoding="async" width="1179" height="481" class="wp-image-7744" src="/wp-content/uploads/2018/06/word-image-346.png" srcset="/wp-content/uploads/2018/06/word-image-346.png 1179w, /wp-content/uploads/2018/06/word-image-346-300x122.png 300w, /wp-content/uploads/2018/06/word-image-346-768x313.png 768w, /wp-content/uploads/2018/06/word-image-346-1024x418.png 1024w" sizes="(max-width: 1179px) 100vw, 1179px" /></p>
<p>注意：表单input设置disabled和readonly的区别</p>
<p>相同点：都不可以编辑input中的数据</p>
<p>不同点：设置disabled时，php中通过$_POST接收不到input框name的属性值</p>
<p>设置readonly时，php中通过$_POST可以收到input的name的属性值</p>
<p>步骤3：定义Auth验证器，进行验证</p>
<p><img loading="lazy" decoding="async" width="773" height="636" class="wp-image-7745" src="/wp-content/uploads/2018/06/word-image-347.png" srcset="/wp-content/uploads/2018/06/word-image-347.png 773w, /wp-content/uploads/2018/06/word-image-347-300x247.png 300w, /wp-content/uploads/2018/06/word-image-347-768x632.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></p>
<p>模板效果：</p>
<p><img loading="lazy" decoding="async" width="542" height="323" class="wp-image-7746" src="/wp-content/uploads/2018/06/word-image-348.png" srcset="/wp-content/uploads/2018/06/word-image-348.png 542w, /wp-content/uploads/2018/06/word-image-348-300x180.png 300w" sizes="(max-width: 542px) 100vw, 542px" /></p>
<h3>完成权限的列表展示</h3>
<h3>完成权限的编辑</h3>
<h3>完成权限的删除</h3>
<h2>角色表的curd操作</h2>
<h3>添加角色及分配权限</h3>
<p>注：一般系统角色名为超级管理员都会拥有所有的权限，其权限字段auth_id_list可以手动设置为*。</p>
<h3>（2）角色的列表展示</h3>
<p>把一个角色所拥有的权限都查出来，这里需要利用到两个mysql函数：</p>
<p>FIND_IN_SET和group_concat(字段)</p>
<ul>
<li>FIND_IN_SET(str,strlist) :</li>
</ul>
<p>作用：查询出子串str，是否在由逗号分隔的目标字符串strlist中存在。</p>
<p>如：判断5是否在字符串1,2,3,4,5中存在：FIND_IN_SET(5,‘1,2,3,4,5’) ，存在则返回所在目标字符串strlist的所在位置，不存在则返回0。</p>
<p><img loading="lazy" decoding="async" width="643" height="83" class="wp-image-7747" src="/wp-content/uploads/2018/06/word-image-349.png" srcset="/wp-content/uploads/2018/06/word-image-349.png 643w, /wp-content/uploads/2018/06/word-image-349-300x39.png 300w" sizes="(max-width: 643px) 100vw, 643px" /> <img loading="lazy" decoding="async" width="476" height="77" class="wp-image-7748" src="/wp-content/uploads/2018/06/word-image-350.png" srcset="/wp-content/uploads/2018/06/word-image-350.png 476w, /wp-content/uploads/2018/06/word-image-350-300x49.png 300w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<ul>
<li>group_concat(字段)</li>
</ul>
<p>作用：主要根据某个字段进行分组，把相同字段的值连接在一起。</p>
<p>默认连接符号是逗号 ，如果用|连接则：</p>
<p>group_concat(字段名 SEPARATOR “|”)</p>
<p>例：如下是表tp_article表中的一些数据</p>
<p><img loading="lazy" decoding="async" width="400" height="150" class="wp-image-7749" src="/wp-content/uploads/2018/06/word-image-351.png" srcset="/wp-content/uploads/2018/06/word-image-351.png 400w, /wp-content/uploads/2018/06/word-image-351-300x113.png 300w" sizes="(max-width: 400px) 100vw, 400px" /></p>
<p>根据cat_id字段进行分组，把具有相同cat_id的title字段值连接在一起。</p>
<p><img loading="lazy" decoding="async" width="766" height="159" class="wp-image-7750" src="/wp-content/uploads/2018/06/word-image-352.png" srcset="/wp-content/uploads/2018/06/word-image-352.png 766w, /wp-content/uploads/2018/06/word-image-352-300x62.png 300w" sizes="(max-width: 766px) 100vw, 766px" /></p>
<h3>（3）完成角色编辑功能</h3>
<h3>（4）完成角色删除功能</h3>
<h1>实现不同用户登录展示不同后台菜单</h1>
<h1>八、权限防翻墙</h1>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7682.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5 商城（二）RBAC、权限增删改查、角色增删改查、不同用户显示不同后台、权限防翻墙</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7751.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7751.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:39:13 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[TP5.0商城]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[RBAC]]></category>
		<category><![CDATA[不同用户显示不同后台]]></category>
		<category><![CDATA[权限增删改查]]></category>
		<category><![CDATA[权限防翻墙]]></category>
		<category><![CDATA[角色增删改查]]></category>
		<guid isPermaLink="false">/?p=7751</guid>

					<description><![CDATA[一、RBAC功能实现 权限表的curd操作 （1）完成权限的添加 步骤1：在后台建立一个Auth控制器，并建立 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>一、RBAC功能实现</h1>
<h2>权限表的curd操作</h2>
<h3>（1）完成权限的添加</h3>
<p>步骤1：在后台建立一个Auth控制器，并建立一个add方法，输出模板内容，并完成添加权限的实现</p>
<p><img loading="lazy" decoding="async" width="1028" height="717" class="wp-image-7825" src="/wp-content/uploads/2018/06/word-image-424.png" srcset="/wp-content/uploads/2018/06/word-image-424.png 1028w, /wp-content/uploads/2018/06/word-image-424-300x209.png 300w, /wp-content/uploads/2018/06/word-image-424-768x536.png 768w, /wp-content/uploads/2018/06/word-image-424-1024x714.png 1024w" sizes="(max-width: 1028px) 100vw, 1028px" /></p>
<p>同时在Auth模型中取出权限的无限级分类数据：</p>
<p><img loading="lazy" decoding="async" width="965" height="680" class="wp-image-7826" src="/wp-content/uploads/2018/06/word-image-425.png" srcset="/wp-content/uploads/2018/06/word-image-425.png 965w, /wp-content/uploads/2018/06/word-image-425-300x211.png 300w, /wp-content/uploads/2018/06/word-image-425-768x541.png 768w" sizes="(max-width: 965px) 100vw, 965px" /></p>
<p>步骤2：设置add.html模板内容</p>
<p><img loading="lazy" decoding="async" width="1230" height="699" class="wp-image-7827" src="/wp-content/uploads/2018/06/word-image-426.png" srcset="/wp-content/uploads/2018/06/word-image-426.png 1230w, /wp-content/uploads/2018/06/word-image-426-300x170.png 300w, /wp-content/uploads/2018/06/word-image-426-768x436.png 768w, /wp-content/uploads/2018/06/word-image-426-1024x582.png 1024w" sizes="(max-width: 1230px) 100vw, 1230px" /></p>
<p>当选择顶级权限时，控制器名和方法名不可用，否则可用。因为顶级权限没有控制器名和方法名。</p>
<p><img loading="lazy" decoding="async" width="1179" height="481" class="wp-image-7828" src="/wp-content/uploads/2018/06/word-image-427.png" srcset="/wp-content/uploads/2018/06/word-image-427.png 1179w, /wp-content/uploads/2018/06/word-image-427-300x122.png 300w, /wp-content/uploads/2018/06/word-image-427-768x313.png 768w, /wp-content/uploads/2018/06/word-image-427-1024x418.png 1024w" sizes="(max-width: 1179px) 100vw, 1179px" /></p>
<p>注意：表单input设置disabled和readonly的区别</p>
<p>相同点：都不可以编辑input中的数据</p>
<p>不同点：设置disabled时，php中通过$_POST接收不到input框name的属性值</p>
<p>设置readonly时，php中通过$_POST可以收到input的name的属性值</p>
<p>步骤3：定义Auth验证器，进行验证</p>
<p><img loading="lazy" decoding="async" width="773" height="636" class="wp-image-7829" src="/wp-content/uploads/2018/06/word-image-428.png" srcset="/wp-content/uploads/2018/06/word-image-428.png 773w, /wp-content/uploads/2018/06/word-image-428-300x247.png 300w, /wp-content/uploads/2018/06/word-image-428-768x632.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></p>
<p>模板效果：</p>
<p><img loading="lazy" decoding="async" width="542" height="323" class="wp-image-7830" src="/wp-content/uploads/2018/06/word-image-429.png" srcset="/wp-content/uploads/2018/06/word-image-429.png 542w, /wp-content/uploads/2018/06/word-image-429-300x180.png 300w" sizes="(max-width: 542px) 100vw, 542px" /></p>
<h3>完成权限的列表展示</h3>
<p>步骤1：在后台的Auth控制器中建立一个index方法，取出所有的权限数据，分配到模板中。</p>
<p><img loading="lazy" decoding="async" width="1021" height="355" class="wp-image-7832" src="/wp-content/uploads/2018/06/word-image-430.png" srcset="/wp-content/uploads/2018/06/word-image-430.png 1021w, /wp-content/uploads/2018/06/word-image-430-300x104.png 300w, /wp-content/uploads/2018/06/word-image-430-768x267.png 768w" sizes="(max-width: 1021px) 100vw, 1021px" /></p>
<p>注：需要指定getAuthsSon方法返回的结果下标值：</p>
<p><img loading="lazy" decoding="async" width="994" height="413" class="wp-image-7833" src="/wp-content/uploads/2018/06/word-image-431.png" srcset="/wp-content/uploads/2018/06/word-image-431.png 994w, /wp-content/uploads/2018/06/word-image-431-300x125.png 300w, /wp-content/uploads/2018/06/word-image-431-768x319.png 768w" sizes="(max-width: 994px) 100vw, 994px" /></p>
<p>步骤：模板中遍历数据</p>
<p><img loading="lazy" decoding="async" width="1267" height="529" class="wp-image-7834" src="/wp-content/uploads/2018/06/word-image-432.png" srcset="/wp-content/uploads/2018/06/word-image-432.png 1267w, /wp-content/uploads/2018/06/word-image-432-300x125.png 300w, /wp-content/uploads/2018/06/word-image-432-768x321.png 768w, /wp-content/uploads/2018/06/word-image-432-1024x428.png 1024w" sizes="(max-width: 1267px) 100vw, 1267px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="967" height="329" class="wp-image-7835" src="/wp-content/uploads/2018/06/word-image-433.png" srcset="/wp-content/uploads/2018/06/word-image-433.png 967w, /wp-content/uploads/2018/06/word-image-433-300x102.png 300w, /wp-content/uploads/2018/06/word-image-433-768x261.png 768w" sizes="(max-width: 967px) 100vw, 967px" /></p>
<h3>完成权限的编辑</h3>
<p>编辑一个角色注意的地方：</p>
<p>a、不能以当前分类作为父权限 b.不能以当前子孙作为父权限</p>
<p>步骤1：修改编辑的链接地址</p>
<p><img loading="lazy" decoding="async" width="1155" height="428" class="wp-image-7836" src="/wp-content/uploads/2018/06/word-image-434.png" srcset="/wp-content/uploads/2018/06/word-image-434.png 1155w, /wp-content/uploads/2018/06/word-image-434-300x111.png 300w, /wp-content/uploads/2018/06/word-image-434-768x285.png 768w, /wp-content/uploads/2018/06/word-image-434-1024x379.png 1024w" sizes="(max-width: 1155px) 100vw, 1155px" /></p>
<p>步骤2：在Auth控制器建立一个upd的完成编辑功能</p>
<p><img loading="lazy" decoding="async" width="1056" height="699" class="wp-image-7837" src="/wp-content/uploads/2018/06/word-image-435.png" srcset="/wp-content/uploads/2018/06/word-image-435.png 1056w, /wp-content/uploads/2018/06/word-image-435-300x199.png 300w, /wp-content/uploads/2018/06/word-image-435-768x508.png 768w, /wp-content/uploads/2018/06/word-image-435-1024x678.png 1024w" sizes="(max-width: 1056px) 100vw, 1056px" /></p>
<p>步骤3：模板回显数据</p>
<p><img loading="lazy" decoding="async" width="1262" height="673" class="wp-image-7838" src="/wp-content/uploads/2018/06/word-image-436.png" srcset="/wp-content/uploads/2018/06/word-image-436.png 1262w, /wp-content/uploads/2018/06/word-image-436-300x160.png 300w, /wp-content/uploads/2018/06/word-image-436-768x410.png 768w, /wp-content/uploads/2018/06/word-image-436-1024x546.png 1024w" sizes="(max-width: 1262px) 100vw, 1262px" /> <img loading="lazy" decoding="async" width="1189" height="503" class="wp-image-7839" src="/wp-content/uploads/2018/06/word-image-437.png" srcset="/wp-content/uploads/2018/06/word-image-437.png 1189w, /wp-content/uploads/2018/06/word-image-437-300x127.png 300w, /wp-content/uploads/2018/06/word-image-437-768x325.png 768w, /wp-content/uploads/2018/06/word-image-437-1024x433.png 1024w" sizes="(max-width: 1189px) 100vw, 1189px" /></p>
<p>步骤4：需要考虑编辑注意的地方</p>
<p>a、不能以当前分类作为父权限 b.不能以当前子孙作为父权限</p>
<p><img loading="lazy" decoding="async" width="671" height="258" class="wp-image-7840" src="/wp-content/uploads/2018/06/word-image-438.png" srcset="/wp-content/uploads/2018/06/word-image-438.png 671w, /wp-content/uploads/2018/06/word-image-438-300x115.png 300w" sizes="(max-width: 671px) 100vw, 671px" /></p>
<p>解决办法：通过js递归实现，把当前权限以及子孙权限给删除即可。</p>
<p><img loading="lazy" decoding="async" width="1249" height="301" class="wp-image-7841" src="/wp-content/uploads/2018/06/word-image-439.png" srcset="/wp-content/uploads/2018/06/word-image-439.png 1249w, /wp-content/uploads/2018/06/word-image-439-300x72.png 300w, /wp-content/uploads/2018/06/word-image-439-768x185.png 768w, /wp-content/uploads/2018/06/word-image-439-1024x247.png 1024w" sizes="(max-width: 1249px) 100vw, 1249px" /> <img loading="lazy" decoding="async" width="1108" height="542" class="wp-image-7842" src="/wp-content/uploads/2018/06/word-image-440.png" srcset="/wp-content/uploads/2018/06/word-image-440.png 1108w, /wp-content/uploads/2018/06/word-image-440-300x147.png 300w, /wp-content/uploads/2018/06/word-image-440-768x376.png 768w, /wp-content/uploads/2018/06/word-image-440-1024x501.png 1024w" sizes="(max-width: 1108px) 100vw, 1108px" /></p>
<h3>【作业】完成权限的删除</h3>
<p>自行完成</p>
<p><img loading="lazy" decoding="async" width="603" height="415" class="wp-image-7843" src="/wp-content/uploads/2018/06/word-image-441.png" srcset="/wp-content/uploads/2018/06/word-image-441.png 603w, /wp-content/uploads/2018/06/word-image-441-300x206.png 300w" sizes="(max-width: 603px) 100vw, 603px" /></p>
<p>未考虑子分类 直接删除全部</p>
<h2>角色表的curd操作</h2>
<p><img loading="lazy" decoding="async" width="749" height="293" class="wp-image-7844" src="/wp-content/uploads/2018/06/word-image-442.png" srcset="/wp-content/uploads/2018/06/word-image-442.png 749w, /wp-content/uploads/2018/06/word-image-442-300x117.png 300w" sizes="(max-width: 749px) 100vw, 749px" /></p>
<p>分析：</p>
<ul>
<li>用户表通过角色字段role_id，找到与其关联的角色表role_id。</li>
<li>角色表通过所拥有的所有权限字段auth_id_list，找到与其关联的权限表的auth_id。</li>
</ul>
<h3>添加角色及分配权限</h3>
<p>步骤1：在后台建立一个Role控制器，并建立一个add方法，获取所有的权限</p>
<p><img loading="lazy" decoding="async" width="1023" height="699" class="wp-image-7845" src="/wp-content/uploads/2018/06/word-image-443.png" srcset="/wp-content/uploads/2018/06/word-image-443.png 1023w, /wp-content/uploads/2018/06/word-image-443-300x205.png 300w, /wp-content/uploads/2018/06/word-image-443-768x525.png 768w" sizes="(max-width: 1023px) 100vw, 1023px" /></p>
<p>我们这里取出所有的权限需要一定技巧，两个：</p>
<p>技巧一：取出所有的权限：并且以auth_id为每个元素的下标。</p>
<p>技巧二：取出所有的权限，通过pid进行分组，把具有相同的pid划分为同一组</p>
<p>其中上面变量$auths和$children的打印结果如下：</p>
<p><img loading="lazy" decoding="async" width="337" height="285" class="wp-image-7846" src="/wp-content/uploads/2018/06/word-image-444.png" srcset="/wp-content/uploads/2018/06/word-image-444.png 337w, /wp-content/uploads/2018/06/word-image-444-300x254.png 300w" sizes="(max-width: 337px) 100vw, 337px" /></p>
<p>其中pid=0,有两个元素即auth_id为46和49。其他以此类推。</p>
<p><img loading="lazy" decoding="async" width="479" height="270" class="wp-image-7847" src="/wp-content/uploads/2018/06/word-image-445.png" srcset="/wp-content/uploads/2018/06/word-image-445.png 479w, /wp-content/uploads/2018/06/word-image-445-300x169.png 300w" sizes="(max-width: 479px) 100vw, 479px" /></p>
<p>步骤2：模板中遍历权限，这里需要参考课件的权限布局文件：</p>
<p><img loading="lazy" decoding="async" width="442" height="67" class="wp-image-7848" src="/wp-content/uploads/2018/06/word-image-446.png" srcset="/wp-content/uploads/2018/06/word-image-446.png 442w, /wp-content/uploads/2018/06/word-image-446-300x45.png 300w" sizes="(max-width: 442px) 100vw, 442px" /></p>
<p>注意：如下一级中有个二级，二级中有三级、</p>
<p><img loading="lazy" decoding="async" width="520" height="106" class="wp-image-7849" src="/wp-content/uploads/2018/06/word-image-447.png" srcset="/wp-content/uploads/2018/06/word-image-447.png 520w, /wp-content/uploads/2018/06/word-image-447-300x61.png 300w" sizes="(max-width: 520px) 100vw, 520px" /> <img loading="lazy" decoding="async" width="1298" height="691" class="wp-image-7850" src="/wp-content/uploads/2018/06/word-image-448.png" srcset="/wp-content/uploads/2018/06/word-image-448.png 1298w, /wp-content/uploads/2018/06/word-image-448-300x160.png 300w, /wp-content/uploads/2018/06/word-image-448-768x409.png 768w, /wp-content/uploads/2018/06/word-image-448-1024x545.png 1024w" sizes="(max-width: 1298px) 100vw, 1298px" /></p>
<p>结果如下：</p>
<p><img loading="lazy" decoding="async" width="680" height="312" class="wp-image-7851" src="/wp-content/uploads/2018/06/word-image-449.png" srcset="/wp-content/uploads/2018/06/word-image-449.png 680w, /wp-content/uploads/2018/06/word-image-449-300x138.png 300w" sizes="(max-width: 680px) 100vw, 680px" /></p>
<p>步骤3：进行添加权限入库</p>
<p><img loading="lazy" decoding="async" width="966" height="529" class="wp-image-7852" src="/wp-content/uploads/2018/06/word-image-450.png" srcset="/wp-content/uploads/2018/06/word-image-450.png 966w, /wp-content/uploads/2018/06/word-image-450-300x164.png 300w, /wp-content/uploads/2018/06/word-image-450-768x421.png 768w" sizes="(max-width: 966px) 100vw, 966px" /></p>
<p>同时给表角色表添加模型和验证器</p>
<p>模型：</p>
<p><img loading="lazy" decoding="async" width="842" height="401" class="wp-image-7853" src="/wp-content/uploads/2018/06/word-image-451.png" srcset="/wp-content/uploads/2018/06/word-image-451.png 842w, /wp-content/uploads/2018/06/word-image-451-300x143.png 300w, /wp-content/uploads/2018/06/word-image-451-768x366.png 768w" sizes="(max-width: 842px) 100vw, 842px" /></p>
<p>验证器：</p>
<p><img loading="lazy" decoding="async" width="707" height="519" class="wp-image-7854" src="/wp-content/uploads/2018/06/word-image-452.png" srcset="/wp-content/uploads/2018/06/word-image-452.png 707w, /wp-content/uploads/2018/06/word-image-452-300x220.png 300w" sizes="(max-width: 707px) 100vw, 707px" /></p>
<p>数据库存储的格式：</p>
<p><img loading="lazy" decoding="async" width="667" height="118" class="wp-image-7855" src="/wp-content/uploads/2018/06/word-image-453.png" srcset="/wp-content/uploads/2018/06/word-image-453.png 667w, /wp-content/uploads/2018/06/word-image-453-300x53.png 300w" sizes="(max-width: 667px) 100vw, 667px" /></p>
<p>注：一般系统角色名为超级管理员都会拥有所有的权限，其权限字段auth_id_list可以手动设置为*。</p>
<h3>（2）完成添加权限分配的特效操作</h3>
<p>role/add.html模板文件：</p>
<p><img loading="lazy" decoding="async" width="1326" height="697" class="wp-image-7856" src="/wp-content/uploads/2018/06/word-image-454.png" srcset="/wp-content/uploads/2018/06/word-image-454.png 1326w, /wp-content/uploads/2018/06/word-image-454-300x158.png 300w, /wp-content/uploads/2018/06/word-image-454-768x404.png 768w, /wp-content/uploads/2018/06/word-image-454-1024x538.png 1024w" sizes="(max-width: 1326px) 100vw, 1326px" /></p>
<p>特效代码：</p>
<p><img loading="lazy" decoding="async" width="912" height="488" class="wp-image-7857" src="/wp-content/uploads/2018/06/word-image-455.png" srcset="/wp-content/uploads/2018/06/word-image-455.png 912w, /wp-content/uploads/2018/06/word-image-455-300x161.png 300w, /wp-content/uploads/2018/06/word-image-455-768x411.png 768w" sizes="(max-width: 912px) 100vw, 912px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="703" height="336" class="wp-image-7858" src="/wp-content/uploads/2018/06/word-image-456.png" srcset="/wp-content/uploads/2018/06/word-image-456.png 703w, /wp-content/uploads/2018/06/word-image-456-300x143.png 300w" sizes="(max-width: 703px) 100vw, 703px" /></p>
<h3>（3）【重要】小结</h3>
<ol>
<li>记住，以后去公司做有关权限分配的时候，可以直接参考以下的模板布局</li>
</ol>
<p><img loading="lazy" decoding="async" width="686" height="76" class="wp-image-7859" src="/wp-content/uploads/2018/06/word-image-457.png" srcset="/wp-content/uploads/2018/06/word-image-457.png 686w, /wp-content/uploads/2018/06/word-image-457-300x33.png 300w" sizes="(max-width: 686px) 100vw, 686px" /></p>
<p>b、以后在模板中凡是需要取出含有（父子孙）层级关系的数据，可以使用下面这个技巧。</p>
<p>技巧一：取出所有的权限：并且以auth_id为每个元素的下标。</p>
<p>技巧二：取出所有的权限，通过pid进行分组，把具有相同的pid划分为同一组</p>
<p>此技巧的典型使用场景有：</p>
<ol>
<li>如遍历权限可以用到，上面代码就是。</li>
</ol>
<p><img loading="lazy" decoding="async" width="617" height="128" class="wp-image-7860" src="/wp-content/uploads/2018/06/word-image-458.png" srcset="/wp-content/uploads/2018/06/word-image-458.png 617w, /wp-content/uploads/2018/06/word-image-458-300x62.png 300w" sizes="(max-width: 617px) 100vw, 617px" /></p>
<ol>
<li>如京东商城遍历三级分类菜单</li>
</ol>
<p><img loading="lazy" decoding="async" width="839" height="53" class="wp-image-7861" src="/wp-content/uploads/2018/06/word-image-459.png" srcset="/wp-content/uploads/2018/06/word-image-459.png 839w, /wp-content/uploads/2018/06/word-image-459-300x19.png 300w, /wp-content/uploads/2018/06/word-image-459-768x49.png 768w" sizes="(max-width: 839px) 100vw, 839px" /></p>
<p>3、分类菜单的折叠</p>
<p><img loading="lazy" decoding="async" width="230" height="342" class="wp-image-7862" src="/wp-content/uploads/2018/06/word-image-460.png" srcset="/wp-content/uploads/2018/06/word-image-460.png 230w, /wp-content/uploads/2018/06/word-image-460-202x300.png 202w" sizes="(max-width: 230px) 100vw, 230px" /></p>
<h3>（4）角色的列表展示</h3>
<p>把一个角色所拥有的权限都查出来，这里需要利用到两个mysql函数：</p>
<p>FIND_IN_SET和group_concat(字段)</p>
<ul>
<li>FIND_IN_SET(str,strlist) :</li>
</ul>
<p>作用：查询出子串str，是否在由逗号分隔的目标字符串strlist中存在。</p>
<p>如：判断5是否在字符串1,2,3,4,5中存在：FIND_IN_SET(5,‘1,2,3,4,5’) ，存在则返回所在目标字符串strlist的所在位置，不存在则返回0。</p>
<p>执行函数mysql函数： select 函数名();</p>
<p><img loading="lazy" decoding="async" width="643" height="83" class="wp-image-7863" src="/wp-content/uploads/2018/06/word-image-461.png" srcset="/wp-content/uploads/2018/06/word-image-461.png 643w, /wp-content/uploads/2018/06/word-image-461-300x39.png 300w" sizes="(max-width: 643px) 100vw, 643px" /> <img loading="lazy" decoding="async" width="476" height="77" class="wp-image-7864" src="/wp-content/uploads/2018/06/word-image-462.png" srcset="/wp-content/uploads/2018/06/word-image-462.png 476w, /wp-content/uploads/2018/06/word-image-462-300x49.png 300w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<ul>
<li>group_concat(字段)</li>
</ul>
<p>作用：主要根据某个字段进行分组，把相同字段的值连接在一起。</p>
<p>默认连接符号是逗号 ，如果用|连接则：</p>
<p>group_concat(字段名 SEPARATOR “|”)</p>
<p>例：如下是表tp_article表中的一些数据</p>
<p><img loading="lazy" decoding="async" width="400" height="150" class="wp-image-7865" src="/wp-content/uploads/2018/06/word-image-463.png" srcset="/wp-content/uploads/2018/06/word-image-463.png 400w, /wp-content/uploads/2018/06/word-image-463-300x113.png 300w" sizes="(max-width: 400px) 100vw, 400px" /></p>
<p>根据cat_id字段进行分组，把具有相同cat_id的title字段值连接在一起。</p>
<p><img loading="lazy" decoding="async" width="766" height="159" class="wp-image-7866" src="/wp-content/uploads/2018/06/word-image-464.png" srcset="/wp-content/uploads/2018/06/word-image-464.png 766w, /wp-content/uploads/2018/06/word-image-464-300x62.png 300w" sizes="(max-width: 766px) 100vw, 766px" /></p>
<p>查询出当前角色所拥有的全部权限拼接在一起：</p>
<p><img loading="lazy" decoding="async" width="1117" height="403" class="wp-image-7867" src="/wp-content/uploads/2018/06/word-image-465.png" srcset="/wp-content/uploads/2018/06/word-image-465.png 1117w, /wp-content/uploads/2018/06/word-image-465-300x108.png 300w, /wp-content/uploads/2018/06/word-image-465-768x277.png 768w, /wp-content/uploads/2018/06/word-image-465-1024x369.png 1024w" sizes="(max-width: 1117px) 100vw, 1117px" /></p>
<h3>完成角色编辑功能（给角色分配权限）</h3>
<p>步骤1：修改role/index.html的链接地址</p>
<p><img loading="lazy" decoding="async" width="1283" height="476" class="wp-image-7868" src="/wp-content/uploads/2018/06/word-image-466.png" srcset="/wp-content/uploads/2018/06/word-image-466.png 1283w, /wp-content/uploads/2018/06/word-image-466-300x111.png 300w, /wp-content/uploads/2018/06/word-image-466-768x285.png 768w, /wp-content/uploads/2018/06/word-image-466-1024x380.png 1024w" sizes="(max-width: 1283px) 100vw, 1283px" /></p>
<p>步骤2：在admin-RoleController-upd的方法中完成数据的回显到模板中</p>
<p>注意： 模块-控制器-方法</p>
<p><img loading="lazy" decoding="async" width="879" height="699" class="wp-image-7869" src="/wp-content/uploads/2018/06/word-image-467.png" srcset="/wp-content/uploads/2018/06/word-image-467.png 879w, /wp-content/uploads/2018/06/word-image-467-300x239.png 300w, /wp-content/uploads/2018/06/word-image-467-768x611.png 768w" sizes="(max-width: 879px) 100vw, 879px" /></p>
<p>步骤3：复制添加角色的add.html模板即可，改名为html.进行回显数据和把角色已有的权限默认选中</p>
<p><img loading="lazy" decoding="async" width="1122" height="620" class="wp-image-7870" src="/wp-content/uploads/2018/06/word-image-468.png" srcset="/wp-content/uploads/2018/06/word-image-468.png 1122w, /wp-content/uploads/2018/06/word-image-468-300x166.png 300w, /wp-content/uploads/2018/06/word-image-468-768x424.png 768w, /wp-content/uploads/2018/06/word-image-468-1024x566.png 1024w" sizes="(max-width: 1122px) 100vw, 1122px" /></p>
<p>已有权限默认选中：</p>
<p><img loading="lazy" decoding="async" width="1160" height="587" class="wp-image-7871" src="/wp-content/uploads/2018/06/word-image-469.png" srcset="/wp-content/uploads/2018/06/word-image-469.png 1160w, /wp-content/uploads/2018/06/word-image-469-300x152.png 300w, /wp-content/uploads/2018/06/word-image-469-768x389.png 768w, /wp-content/uploads/2018/06/word-image-469-1024x518.png 1024w" sizes="(max-width: 1160px) 100vw, 1160px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="661" height="295" class="wp-image-7872" src="/wp-content/uploads/2018/06/word-image-470.png" srcset="/wp-content/uploads/2018/06/word-image-470.png 661w, /wp-content/uploads/2018/06/word-image-470-300x134.png 300w" sizes="(max-width: 661px) 100vw, 661px" /></p>
<h3>（6）【作业】完成角色删除功能</h3>
<p>自行完成</p>
<p><img loading="lazy" decoding="async" width="636" height="397" class="wp-image-7873" src="/wp-content/uploads/2018/06/word-image-471.png" srcset="/wp-content/uploads/2018/06/word-image-471.png 636w, /wp-content/uploads/2018/06/word-image-471-300x187.png 300w" sizes="(max-width: 636px) 100vw, 636px" /></p>
<h3>（7）添加用户分配权限</h3>
<p>步骤1：修改admin-view-user-add.html模板内容，加一个显示角色的下拉框</p>
<h1>实现不同用户登录展示不同后台菜单</h1>
<h2>思路</h2>
<p><img loading="lazy" decoding="async" width="848" height="291" class="wp-image-7874" src="/wp-content/uploads/2018/06/word-image-472.png" srcset="/wp-content/uploads/2018/06/word-image-472.png 848w, /wp-content/uploads/2018/06/word-image-472-300x103.png 300w, /wp-content/uploads/2018/06/word-image-472-768x264.png 768w" sizes="(max-width: 848px) 100vw, 848px" /></p>
<ol>
<li>用户登录成功的时候，获取到role_id。</li>
<li>通过role_id获取角色表的auth_id_list字段</li>
<li>通过权限表auth_id 只要在auth_id_list字段存在即可，查出所拥有的权限</li>
</ol>
<p>超级管理员auth_id_list字段的值为*，代表拥有后台操作的所有权限。</p>
<h2>代码实现</h2>
<p>步骤1：在用户登录成功的模型的checkUser方法中，通过角色id把当前角色所有的权限写入到session。</p>
<p><img loading="lazy" decoding="async" width="973" height="627" class="wp-image-7875" src="/wp-content/uploads/2018/06/word-image-473.png" srcset="/wp-content/uploads/2018/06/word-image-473.png 973w, /wp-content/uploads/2018/06/word-image-473-300x193.png 300w, /wp-content/uploads/2018/06/word-image-473-768x495.png 768w" sizes="(max-width: 973px) 100vw, 973px" /></p>
<p>步骤2：定义user模型中定义writeAuthToSession方法把权限写入到session中</p>
<p>注：后台left.html模板文件中，只需要显示一级和二级的权限即可：</p>
<p>我们需要构造出一个特定数据结构的数据：</p>
<p>如下：通过每个顶级（pid=0）的元素加个一个sonsAuth下标存储其对应的子级权限</p>
<p>[</p>
<p>auth_name=&gt;‘用户管理’</p>
<p>auth_id =&gt;46</p>
<p>pid =&gt; 0</p>
<p>&#8230;&#8230;</p>
<p>sonsAuth=&gt;[</p>
<p>[auth_name=&gt;用户列表,’pid’=&gt;46]</p>
<p>[auth_name=&gt;用户添加,’pid’=&gt;46]</p>
<p>&#8230;..</p>
<p>]</p>
<p>]</p>
<p>超级管理员：</p>
<p><img loading="lazy" decoding="async" width="1265" height="387" class="wp-image-7876" src="/wp-content/uploads/2018/06/word-image-474.png" srcset="/wp-content/uploads/2018/06/word-image-474.png 1265w, /wp-content/uploads/2018/06/word-image-474-300x92.png 300w, /wp-content/uploads/2018/06/word-image-474-768x235.png 768w, /wp-content/uploads/2018/06/word-image-474-1024x313.png 1024w" sizes="(max-width: 1265px) 100vw, 1265px" /></p>
<p>非超级管理员：</p>
<p><img loading="lazy" decoding="async" width="1163" height="577" class="wp-image-7877" src="/wp-content/uploads/2018/06/word-image-475.png" srcset="/wp-content/uploads/2018/06/word-image-475.png 1163w, /wp-content/uploads/2018/06/word-image-475-300x149.png 300w, /wp-content/uploads/2018/06/word-image-475-768x381.png 768w, /wp-content/uploads/2018/06/word-image-475-1024x508.png 1024w" sizes="(max-width: 1163px) 100vw, 1163px" /></p>
<p>步骤3：在left.html取出session中的权限，遍历访问的菜单</p>
<p><img loading="lazy" decoding="async" width="1235" height="668" class="wp-image-7878" src="/wp-content/uploads/2018/06/word-image-476.png" srcset="/wp-content/uploads/2018/06/word-image-476.png 1235w, /wp-content/uploads/2018/06/word-image-476-300x162.png 300w, /wp-content/uploads/2018/06/word-image-476-768x415.png 768w, /wp-content/uploads/2018/06/word-image-476-1024x554.png 1024w" sizes="(max-width: 1235px) 100vw, 1235px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="219" height="159" class="wp-image-7879" src="/wp-content/uploads/2018/06/word-image-477.png" /></p>
<h1>权限防翻墙</h1>
<p>如下：</p>
<p><img loading="lazy" decoding="async" width="1347" height="258" class="wp-image-7880" src="/wp-content/uploads/2018/06/word-image-478.png" srcset="/wp-content/uploads/2018/06/word-image-478.png 1347w, /wp-content/uploads/2018/06/word-image-478-300x57.png 300w, /wp-content/uploads/2018/06/word-image-478-768x147.png 768w, /wp-content/uploads/2018/06/word-image-478-1024x196.png 1024w" sizes="(max-width: 1347px) 100vw, 1347px" /></p>
<p>解决办法：在common控制器中的_initialize的方法中，做防翻墙的操作。</p>
<p>1、要先获取到用户所访问的控制器名和方法名，在去做相关判断是否有权限</p>
<p><img loading="lazy" decoding="async" width="1111" height="626" class="wp-image-7881" src="/wp-content/uploads/2018/06/word-image-479.png" srcset="/wp-content/uploads/2018/06/word-image-479.png 1111w, /wp-content/uploads/2018/06/word-image-479-300x169.png 300w, /wp-content/uploads/2018/06/word-image-479-768x433.png 768w, /wp-content/uploads/2018/06/word-image-479-1024x577.png 1024w" sizes="(max-width: 1111px) 100vw, 1111px" /></p>
<ol>
<li>把用户可以访问的权限存储在session中</li>
</ol>
<p>超级管理员：</p>
<p><img loading="lazy" decoding="async" width="1240" height="517" class="wp-image-7882" src="/wp-content/uploads/2018/06/word-image-480.png" srcset="/wp-content/uploads/2018/06/word-image-480.png 1240w, /wp-content/uploads/2018/06/word-image-480-300x125.png 300w, /wp-content/uploads/2018/06/word-image-480-768x320.png 768w, /wp-content/uploads/2018/06/word-image-480-1024x427.png 1024w" sizes="(max-width: 1240px) 100vw, 1240px" /></p>
<p>非超级管理员：</p>
<p><img loading="lazy" decoding="async" width="998" height="625" class="wp-image-7883" src="/wp-content/uploads/2018/06/word-image-481.png" srcset="/wp-content/uploads/2018/06/word-image-481.png 998w, /wp-content/uploads/2018/06/word-image-481-300x188.png 300w, /wp-content/uploads/2018/06/word-image-481-768x481.png 768w" sizes="(max-width: 998px) 100vw, 998px" /></p>
<p>今天重点：</p>
<ol>
<li>一张牛逼的图</li>
<li>怎么构造满足我们要求的数组结构数据</li>
</ol>
<h1>四、商品有关的基本概念</h1>
<p>这里主要涉及到以下几个概念：</p>
<ul>
<li>商品类型：不同的网站的卖的商品是不一样的，比如化妆品网站专门卖化妆品、手机网站专门卖手机、汽车网站专门卖汽车。</li>
<li>商品属性：不同的商品类型对应的商品属性也是不一样的。</li>
</ul>
<p>比如卖汽车网站，商品(汽车)属性有轴距、变速箱、驱动方式、进气方式、排量等</p>
<p>比如卖电脑网站，商品（电脑）属性有尺寸、内存、cpu、操作系统、系统核数等</p>
<p>比如卖手机网站，商品（手机）属性有尺寸、内存、系统、颜色、网络类型、电池容量等</p>
<p>商品类型决定了商品属性</p>
<ul>
<li>商品分类</li>
</ul>
<p>一个电商网站卖的商品不一样，其商品分类也是不一样的。</p>
<p>比如：卖汽车分类有：国产（吉利、 广汽）、日产(本田、丰田)、德国（奔驰、宝马）、韩国（起亚、现代）。</p>
<p>比如：卖手机分类有: 小米、华为、三星、苹果、oppo、vivo、魅族。</p>
<ul>
<li>商品（产品+属性=商品）</li>
</ul>
<p>如：iphoneX+64G , iphoneX+256G</p>
<h3>商品类型</h3>
<p>不同的商品类型会有不同的属性</p>
<p>可以在ecshop后台中新建一个商品类型，如下：建立一个汽车商品类型</p>
<p><img loading="lazy" decoding="async" width="1344" height="238" class="wp-image-7884" src="/wp-content/uploads/2018/06/word-image-482.png" srcset="/wp-content/uploads/2018/06/word-image-482.png 1344w, /wp-content/uploads/2018/06/word-image-482-300x53.png 300w, /wp-content/uploads/2018/06/word-image-482-768x136.png 768w, /wp-content/uploads/2018/06/word-image-482-1024x181.png 1024w" sizes="(max-width: 1344px) 100vw, 1344px" /> <img loading="lazy" decoding="async" width="797" height="395" class="wp-image-7885" src="/wp-content/uploads/2018/06/word-image-483.png" srcset="/wp-content/uploads/2018/06/word-image-483.png 797w, /wp-content/uploads/2018/06/word-image-483-300x149.png 300w, /wp-content/uploads/2018/06/word-image-483-768x381.png 768w" sizes="(max-width: 797px) 100vw, 797px" /></p>
<p>属性分组：有些属性是可以归为一组的，参考京东电脑商品：</p>
<p><img loading="lazy" decoding="async" width="546" height="381" class="wp-image-7886" src="/wp-content/uploads/2018/06/word-image-484.png" srcset="/wp-content/uploads/2018/06/word-image-484.png 546w, /wp-content/uploads/2018/06/word-image-484-300x209.png 300w" sizes="(max-width: 546px) 100vw, 546px" /></p>
<h3>商品属性</h3>
<p>给商品类型添加商品属性： 商品类型&#8211;&gt;属性列表：</p>
<p><img loading="lazy" decoding="async" width="1147" height="34" class="wp-image-7887" src="/wp-content/uploads/2018/06/word-image-485.png" srcset="/wp-content/uploads/2018/06/word-image-485.png 1147w, /wp-content/uploads/2018/06/word-image-485-300x9.png 300w, /wp-content/uploads/2018/06/word-image-485-768x23.png 768w, /wp-content/uploads/2018/06/word-image-485-1024x30.png 1024w" sizes="(max-width: 1147px) 100vw, 1147px" /> <img loading="lazy" decoding="async" width="1142" height="200" class="wp-image-7888" src="/wp-content/uploads/2018/06/word-image-486.png" srcset="/wp-content/uploads/2018/06/word-image-486.png 1142w, /wp-content/uploads/2018/06/word-image-486-300x53.png 300w, /wp-content/uploads/2018/06/word-image-486-768x135.png 768w, /wp-content/uploads/2018/06/word-image-486-1024x179.png 1024w" sizes="(max-width: 1142px) 100vw, 1142px" /></p>
<p>给汽车类型商品添加进气方式的属性：</p>
<p><img loading="lazy" decoding="async" width="658" height="419" class="wp-image-7889" src="/wp-content/uploads/2018/06/word-image-487.png" srcset="/wp-content/uploads/2018/06/word-image-487.png 658w, /wp-content/uploads/2018/06/word-image-487-300x191.png 300w" sizes="(max-width: 658px) 100vw, 658px" /></p>
<p>单选属性： 指买商品的时候，可以选择一个属性，不同的属性价格不一样</p>
<p><img loading="lazy" decoding="async" width="676" height="145" class="wp-image-7890" src="/wp-content/uploads/2018/06/word-image-488.png" srcset="/wp-content/uploads/2018/06/word-image-488.png 676w, /wp-content/uploads/2018/06/word-image-488-300x64.png 300w" sizes="(max-width: 676px) 100vw, 676px" /></p>
<p>唯一属性：只能看不能选。</p>
<p><img loading="lazy" decoding="async" width="802" height="232" class="wp-image-7891" src="/wp-content/uploads/2018/06/word-image-489.png" srcset="/wp-content/uploads/2018/06/word-image-489.png 802w, /wp-content/uploads/2018/06/word-image-489-300x87.png 300w, /wp-content/uploads/2018/06/word-image-489-768x222.png 768w" sizes="(max-width: 802px) 100vw, 802px" /></p>
<p>复选属性：可以选择多个，一般买商品的附加配件都是复选的。</p>
<p><img loading="lazy" decoding="async" width="1016" height="261" class="wp-image-7892" src="/wp-content/uploads/2018/06/word-image-490.png" srcset="/wp-content/uploads/2018/06/word-image-490.png 1016w, /wp-content/uploads/2018/06/word-image-490-300x77.png 300w, /wp-content/uploads/2018/06/word-image-490-768x197.png 768w" sizes="(max-width: 1016px) 100vw, 1016px" /></p>
<p>当在后台添加一个商品的时候要选择一个商品类型，选择了一个商品类型就决定了这个商品的有哪些属性，如下是添加商品设置其商品属性：</p>
<p><img loading="lazy" decoding="async" width="921" height="440" class="wp-image-7893" src="/wp-content/uploads/2018/06/word-image-491.png" srcset="/wp-content/uploads/2018/06/word-image-491.png 921w, /wp-content/uploads/2018/06/word-image-491-300x143.png 300w, /wp-content/uploads/2018/06/word-image-491-768x367.png 768w" sizes="(max-width: 921px) 100vw, 921px" /></p>
<p>添加属性的特点：</p>
<p>唯一属性（只能看，不能选）：前面没有【+】，不可以设置价格</p>
<p>单选属性（可选择）：前面有【+】，点击+即可复制多个，不同的单选属性可设置不同的价格</p>
<p>属性值手工输入：对应的是个input框，需要自己输入。</p>
<p>属性值是列表选择： 对应的是个select下拉框，需选中一个属性值。</p>
<h3>商品分类</h3>
<p>一般一个网站决定卖什么类型商品就决定了其商品分类。</p>
<p>如卖汽车网站：分类有国产、日系、德系、韩系等</p>
<p>如卖化妆品网站：分类洗面奶、乳液、面膜、保湿、祛痘、眼霜等</p>
<p><img loading="lazy" decoding="async" width="1323" height="236" class="wp-image-7894" src="/wp-content/uploads/2018/06/word-image-492.png" srcset="/wp-content/uploads/2018/06/word-image-492.png 1323w, /wp-content/uploads/2018/06/word-image-492-300x54.png 300w, /wp-content/uploads/2018/06/word-image-492-768x137.png 768w, /wp-content/uploads/2018/06/word-image-492-1024x183.png 1024w" sizes="(max-width: 1323px) 100vw, 1323px" /></p>
<h1>五、完成商品类型的curd</h1>
<h2>商品类型介绍</h2>
<p>商品类型：不同的网站的卖的商品类型是不一样的，比如化妆品网站专卖化妆品、手机网站专卖手机、二手汽车网站专买二手汽车。</p>
<p>网站决定卖什么商品类型，也就决定了商品的商品属性</p>
<h2>商品类型的增加</h2>
<h2>商品类型的列表</h2>
<h2>商品类型的编辑</h2>
<h2>【作业】商品类型的删除</h2>
<h1>六、完成商品属性的curd</h1>
<h2>1、商品属性的认识</h2>
<p>网站决定卖什么商品类型，也就决定了商品的商品属性</p>
<p>可以参考ecshop添加属性的方式:</p>
<p><img loading="lazy" decoding="async" width="960" height="427" class="wp-image-7895" src="/wp-content/uploads/2018/06/word-image-493.png" srcset="/wp-content/uploads/2018/06/word-image-493.png 960w, /wp-content/uploads/2018/06/word-image-493-300x133.png 300w, /wp-content/uploads/2018/06/word-image-493-768x342.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p>属性这里重点两种属性：唯一属性和单选属性</p>
<p>唯一属性：只能看，不能选。</p>
<p><img loading="lazy" decoding="async" width="389" height="55" class="wp-image-7896" src="/wp-content/uploads/2018/06/word-image-494.png" srcset="/wp-content/uploads/2018/06/word-image-494.png 389w, /wp-content/uploads/2018/06/word-image-494-300x42.png 300w" sizes="(max-width: 389px) 100vw, 389px" /></p>
<p>单选属性：我们购买商品的时候，可以选择的，后面添加商品的时候，不同的单选属性价格也是不一样的，如iphone6银色和iphone黑色价格是不一样的。</p>
<p><img loading="lazy" decoding="async" width="678" height="186" class="wp-image-7897" src="/wp-content/uploads/2018/06/word-image-495.png" srcset="/wp-content/uploads/2018/06/word-image-495.png 678w, /wp-content/uploads/2018/06/word-image-495-300x82.png 300w" sizes="(max-width: 678px) 100vw, 678px" /></p>
<p>②属性的值的录入方式</p>
<p><img loading="lazy" decoding="async" width="643" height="114" class="wp-image-7898" src="/wp-content/uploads/2018/06/word-image-496.png" srcset="/wp-content/uploads/2018/06/word-image-496.png 643w, /wp-content/uploads/2018/06/word-image-496-300x53.png 300w" sizes="(max-width: 643px) 100vw, 643px" /></p>
<p>手工输入：不可以输入属性值，且可选值列表是禁用状态，只能在添加商品的时候输入属性值。</p>
<p>列表选择：在可选择列表输入一些我们指定的属性值，添加商品的时候，从中选中一个属性值即可。</p>
<p>表结构：</p>
<h2>完成商品属性的添加</h2>
<h2>完成商品属性的列表</h2>
<h2>完成商品属性的编辑</h2>
<h2>完成商品属性的删除</h2>
<h2>完成商品类型列表中属性的查看</h2>
<h1>七、完成商品分类的curd</h1>
<h2>1、分析分类表结构</h2>
<p>表字段结构如下：</p>
<h2>完成商品分类的添加</h2>
<h2>完成商品分类的列表</h2>
<h2>4、完成商品分类的编辑</h2>
<h2>5、【作业】完成商品分类的删除</h2>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7751.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TP5 商城（三）账户状态权限控制、商品类型 CURD、商品属性 CURD、商品分类 CURD</title>
		<link>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7899.html</link>
					<comments>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7899.html#respond</comments>
		
		<dc:creator><![CDATA[Mr.Lee]]></dc:creator>
		<pubDate>Sat, 09 Jun 2018 00:38:08 +0000</pubDate>
				<category><![CDATA[TP5.0]]></category>
		<category><![CDATA[TP5.0商城]]></category>
		<category><![CDATA[后台框架]]></category>
		<category><![CDATA[商品分类 CURD]]></category>
		<category><![CDATA[商品属性 CURD]]></category>
		<category><![CDATA[商品类型 CURD]]></category>
		<category><![CDATA[账户状态权限控制]]></category>
		<guid isPermaLink="false">/?p=7899</guid>

					<description><![CDATA[完善控制账户状态的权限控制 当用户点击下面列表的可用或禁用的功能的时候，ajax返回一个无权限操作。 这是因为 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>完善控制账户状态的权限控制</h1>
<p>当用户点击下面列表的可用或禁用的功能的时候，ajax返回一个无权限操作。</p>
<p>这是因为用户没有此权限，一般只有超级管理员才会有此权限。</p>
<p>所以，我们也可以在后台添加此权限给用户进行分配：</p>
<p><img loading="lazy" decoding="async" width="558" height="375" class="wp-image-7965" src="/wp-content/uploads/2018/06/word-image-560.png" srcset="/wp-content/uploads/2018/06/word-image-560.png 558w, /wp-content/uploads/2018/06/word-image-560-300x202.png 300w" sizes="(max-width: 558px) 100vw, 558px" /></p>
<p>然后给对应的角色分配即可：</p>
<p><img loading="lazy" decoding="async" width="721" height="347" class="wp-image-7966" src="/wp-content/uploads/2018/06/word-image-561.png" srcset="/wp-content/uploads/2018/06/word-image-561.png 721w, /wp-content/uploads/2018/06/word-image-561-300x144.png 300w" sizes="(max-width: 721px) 100vw, 721px" /></p>
<p>同时当某个角色没有此权限的时候，需要在Common控制器中给提示无权限访问：</p>
<p><img loading="lazy" decoding="async" width="1286" height="694" class="wp-image-7967" src="/wp-content/uploads/2018/06/word-image-562.png" srcset="/wp-content/uploads/2018/06/word-image-562.png 1286w, /wp-content/uploads/2018/06/word-image-562-300x162.png 300w, /wp-content/uploads/2018/06/word-image-562-768x414.png 768w, /wp-content/uploads/2018/06/word-image-562-1024x553.png 1024w" sizes="(max-width: 1286px) 100vw, 1286px" /></p>
<p>在ajax中给出提示无权限：</p>
<p><img loading="lazy" decoding="async" width="1210" height="427" class="wp-image-7968" src="/wp-content/uploads/2018/06/word-image-563.png" srcset="/wp-content/uploads/2018/06/word-image-563.png 1210w, /wp-content/uploads/2018/06/word-image-563-300x106.png 300w, /wp-content/uploads/2018/06/word-image-563-768x271.png 768w, /wp-content/uploads/2018/06/word-image-563-1024x361.png 1024w" sizes="(max-width: 1210px) 100vw, 1210px" /></p>
<h1>一、商品有关的基本概念</h1>
<p>这里主要涉及到以下几个概念：</p>
<ul>
<li>商品类型：不同的网站的卖的商品是不一样的，比如化妆品网站专门卖化妆品、手机网站专门卖手机、汽车网站专门卖汽车。</li>
<li>商品属性：不同的商品类型对应的商品属性也是不一样的。</li>
</ul>
<p>比如卖汽车网站，商品(汽车)属性有轴距、变速箱、驱动方式、进气方式、排量等</p>
<p>比如卖电脑网站，商品（电脑）属性有尺寸、内存、cpu、操作系统、系统核数等</p>
<p>比如卖手机网站，商品（手机）属性有尺寸、内存、系统、颜色、网络类型、电池容量等</p>
<p>商品类型决定了商品属性，商品属性依据商品类型走的。</p>
<ul>
<li>商品分类</li>
</ul>
<p>一个电商网站卖的商品不一样，其商品分类也是不一样的。</p>
<p>比如：卖汽车分类有：国产（吉利、 广汽）、日产(本田、丰田)、德国（奔驰、宝马）、韩国（起亚、现代）。</p>
<p>比如：卖手机分类有: 小米、华为、三星、苹果、oppo、vivo、魅族。</p>
<p>比如：卖化妆品有: 补水、祛痘、气垫、BB霜、口红、&#8230;.</p>
<ul>
<li>商品（产品+属性=商品）</li>
<li>商品（产品+属性=商品）</li>
</ul>
<p>如：iphoneX+64G(7888) , iphoneX+256G(9888)</p>
<h2>1、商品类型</h2>
<p>不同的商品类型会有不同的属性</p>
<p>可以在ecshop后台中新建一个商品类型，如下：建立一个手机商品类型</p>
<p><img loading="lazy" decoding="async" width="1344" height="238" class="wp-image-7969" src="/wp-content/uploads/2018/06/word-image-564.png" srcset="/wp-content/uploads/2018/06/word-image-564.png 1344w, /wp-content/uploads/2018/06/word-image-564-300x53.png 300w, /wp-content/uploads/2018/06/word-image-564-768x136.png 768w, /wp-content/uploads/2018/06/word-image-564-1024x181.png 1024w" sizes="(max-width: 1344px) 100vw, 1344px" /></p>
<h2>2、商品属性</h2>
<p>给商品类型添加商品属性： 商品类型&#8211;&gt;属性列表：</p>
<p><img loading="lazy" decoding="async" width="1147" height="34" class="wp-image-7970" src="/wp-content/uploads/2018/06/word-image-565.png" srcset="/wp-content/uploads/2018/06/word-image-565.png 1147w, /wp-content/uploads/2018/06/word-image-565-300x9.png 300w, /wp-content/uploads/2018/06/word-image-565-768x23.png 768w, /wp-content/uploads/2018/06/word-image-565-1024x30.png 1024w" sizes="(max-width: 1147px) 100vw, 1147px" /> <img loading="lazy" decoding="async" width="1159" height="102" class="wp-image-7972" src="/wp-content/uploads/2018/06/word-image-566.png" srcset="/wp-content/uploads/2018/06/word-image-566.png 1159w, /wp-content/uploads/2018/06/word-image-566-300x26.png 300w, /wp-content/uploads/2018/06/word-image-566-768x68.png 768w, /wp-content/uploads/2018/06/word-image-566-1024x90.png 1024w" sizes="(max-width: 1159px) 100vw, 1159px" /></p>
<p>给手机类型商品添加内存的属性：</p>
<p><img loading="lazy" decoding="async" width="665" height="370" class="wp-image-7973" src="/wp-content/uploads/2018/06/word-image-567.png" srcset="/wp-content/uploads/2018/06/word-image-567.png 665w, /wp-content/uploads/2018/06/word-image-567-300x167.png 300w" sizes="(max-width: 665px) 100vw, 665px" /></p>
<p>添加商品属性列表如下：</p>
<p><img loading="lazy" decoding="async" width="955" height="200" class="wp-image-7974" src="/wp-content/uploads/2018/06/word-image-568.png" srcset="/wp-content/uploads/2018/06/word-image-568.png 955w, /wp-content/uploads/2018/06/word-image-568-300x63.png 300w, /wp-content/uploads/2018/06/word-image-568-768x161.png 768w" sizes="(max-width: 955px) 100vw, 955px" /></p>
<p>属性解释：</p>
<p>单选属性： 指买商品的时候，可以选择一个属性，不同的属性价格不一样</p>
<p><img loading="lazy" decoding="async" width="676" height="145" class="wp-image-7975" src="/wp-content/uploads/2018/06/word-image-569.png" srcset="/wp-content/uploads/2018/06/word-image-569.png 676w, /wp-content/uploads/2018/06/word-image-569-300x64.png 300w" sizes="(max-width: 676px) 100vw, 676px" /></p>
<p>唯一属性：只能看不能选。</p>
<p><img loading="lazy" decoding="async" width="802" height="232" class="wp-image-7976" src="/wp-content/uploads/2018/06/word-image-570.png" srcset="/wp-content/uploads/2018/06/word-image-570.png 802w, /wp-content/uploads/2018/06/word-image-570-300x87.png 300w, /wp-content/uploads/2018/06/word-image-570-768x222.png 768w" sizes="(max-width: 802px) 100vw, 802px" /></p>
<p>复选属性：可以选择多个，一般买商品的附加配件都是复选的。</p>
<p><img loading="lazy" decoding="async" width="1016" height="261" class="wp-image-7977" src="/wp-content/uploads/2018/06/word-image-571.png" srcset="/wp-content/uploads/2018/06/word-image-571.png 1016w, /wp-content/uploads/2018/06/word-image-571-300x77.png 300w, /wp-content/uploads/2018/06/word-image-571-768x197.png 768w" sizes="(max-width: 1016px) 100vw, 1016px" /></p>
<h2>3、属性类型和属性录入方式的组合</h2>
<p>当在后台添加一个商品的时候要选择一个商品类型，选择了一个商品类型就决定了这个商品的有哪些属性，如下是添加商品设置其商品属性：</p>
<p><img loading="lazy" decoding="async" width="359" height="255" class="wp-image-7978" src="/wp-content/uploads/2018/06/word-image-572.png" srcset="/wp-content/uploads/2018/06/word-image-572.png 359w, /wp-content/uploads/2018/06/word-image-572-300x213.png 300w" sizes="(max-width: 359px) 100vw, 359px" /></p>
<p>给商品添加属性：</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" width="794" height="225" class="wp-image-7979" src="/wp-content/uploads/2018/06/word-image-573.png" srcset="/wp-content/uploads/2018/06/word-image-573.png 794w, /wp-content/uploads/2018/06/word-image-573-300x85.png 300w, /wp-content/uploads/2018/06/word-image-573-768x218.png 768w" sizes="(max-width: 794px) 100vw, 794px" /></p>
<p>特点如下：</p>
<p>唯一属性（只能看，不能选）：前面没有【+】，不可以设置价格</p>
<p>单选属性（可选择）：前面有【+】，点击+即可复制多个，不同的单选属性可设置不同的价格</p>
<p>属性值手工输入：对应的是个input框，需要自己输入。</p>
<p>属性值是列表选择： 对应的是个select下拉框，需选中一个属性值。</p>
<h2>4、商品分类</h2>
<p>一般一个网站决定卖什么类型商品就决定了其商品分类。</p>
<p>如卖汽车网站：分类有国产、日系、德系、韩系等</p>
<p>如卖化妆品网站：分类洗面奶、乳液、面膜、保湿、祛痘、眼霜等</p>
<p><img loading="lazy" decoding="async" width="1323" height="236" class="wp-image-7980" src="/wp-content/uploads/2018/06/word-image-574.png" srcset="/wp-content/uploads/2018/06/word-image-574.png 1323w, /wp-content/uploads/2018/06/word-image-574-300x54.png 300w, /wp-content/uploads/2018/06/word-image-574-768x137.png 768w, /wp-content/uploads/2018/06/word-image-574-1024x183.png 1024w" sizes="(max-width: 1323px) 100vw, 1323px" /></p>
<h1>二、完成商品类型的curd</h1>
<h2>商品类型介绍</h2>
<p>商品类型：不同的网站的卖的商品类型是不一样的，比如化妆品网站专卖化妆品、手机网站专卖手机、二手汽车网站专买二手汽车。</p>
<p>网站决定卖什么商品类型，也就决定了商品的商品属性</p>
<h2>商品类型的增加</h2>
<p>商品类型表如下:</p>
<p><img loading="lazy" decoding="async" width="986" height="155" class="wp-image-7981" src="/wp-content/uploads/2018/06/word-image-575.png" srcset="/wp-content/uploads/2018/06/word-image-575.png 986w, /wp-content/uploads/2018/06/word-image-575-300x47.png 300w, /wp-content/uploads/2018/06/word-image-575-768x121.png 768w" sizes="(max-width: 986px) 100vw, 986px" /></p>
<p>1：在admin-TypeController-add中，完成添加商品类型完成</p>
<p><img loading="lazy" decoding="async" width="1038" height="519" class="wp-image-7982" src="/wp-content/uploads/2018/06/word-image-576.png" srcset="/wp-content/uploads/2018/06/word-image-576.png 1038w, /wp-content/uploads/2018/06/word-image-576-300x150.png 300w, /wp-content/uploads/2018/06/word-image-576-768x384.png 768w, /wp-content/uploads/2018/06/word-image-576-1024x512.png 1024w" sizes="(max-width: 1038px) 100vw, 1038px" /></p>
<ol>
<li>在add模板中设置表单name名称</li>
</ol>
<p><img loading="lazy" decoding="async" width="1263" height="589" class="wp-image-7983" src="/wp-content/uploads/2018/06/word-image-577.png" srcset="/wp-content/uploads/2018/06/word-image-577.png 1263w, /wp-content/uploads/2018/06/word-image-577-300x140.png 300w, /wp-content/uploads/2018/06/word-image-577-768x358.png 768w, /wp-content/uploads/2018/06/word-image-577-1024x478.png 1024w" sizes="(max-width: 1263px) 100vw, 1263px" /></p>
<p>3、同时建立一个Type的验证器和Type模型</p>
<p>验证器：</p>
<p><img loading="lazy" decoding="async" width="888" height="523" class="wp-image-7984" src="/wp-content/uploads/2018/06/word-image-578.png" srcset="/wp-content/uploads/2018/06/word-image-578.png 888w, /wp-content/uploads/2018/06/word-image-578-300x177.png 300w, /wp-content/uploads/2018/06/word-image-578-768x452.png 768w" sizes="(max-width: 888px) 100vw, 888px" /></p>
<p>模型：</p>
<p><img loading="lazy" decoding="async" width="796" height="268" class="wp-image-7985" src="/wp-content/uploads/2018/06/word-image-579.png" srcset="/wp-content/uploads/2018/06/word-image-579.png 796w, /wp-content/uploads/2018/06/word-image-579-300x101.png 300w, /wp-content/uploads/2018/06/word-image-579-768x259.png 768w" sizes="(max-width: 796px) 100vw, 796px" /></p>
<h2>商品类型的列表</h2>
<ol>
<li>在admin-Type-index方法中取出所有的商品类型分配到模板中</li>
</ol>
<p><img loading="lazy" decoding="async" width="746" height="314" class="wp-image-7986" src="/wp-content/uploads/2018/06/word-image-580.png" srcset="/wp-content/uploads/2018/06/word-image-580.png 746w, /wp-content/uploads/2018/06/word-image-580-300x126.png 300w" sizes="(max-width: 746px) 100vw, 746px" /></p>
<ol>
<li>index.html模板中遍历数据</li>
</ol>
<p><img loading="lazy" decoding="async" width="1263" height="493" class="wp-image-7987" src="/wp-content/uploads/2018/06/word-image-581.png" srcset="/wp-content/uploads/2018/06/word-image-581.png 1263w, /wp-content/uploads/2018/06/word-image-581-300x117.png 300w, /wp-content/uploads/2018/06/word-image-581-768x300.png 768w, /wp-content/uploads/2018/06/word-image-581-1024x400.png 1024w" sizes="(max-width: 1263px) 100vw, 1263px" /></p>
<h2>商品类型的编辑</h2>
<ol>
<li>修改index.html的编辑的链接地址</li>
</ol>
<p><img loading="lazy" decoding="async" width="1201" height="404" class="wp-image-7988" src="/wp-content/uploads/2018/06/word-image-582.png" srcset="/wp-content/uploads/2018/06/word-image-582.png 1201w, /wp-content/uploads/2018/06/word-image-582-300x101.png 300w, /wp-content/uploads/2018/06/word-image-582-768x258.png 768w, /wp-content/uploads/2018/06/word-image-582-1024x344.png 1024w" sizes="(max-width: 1201px) 100vw, 1201px" /></p>
<p>2、在admin-type-upd方法中完取出当前商品类型的数据回显到模板中，并完成编辑入库的实现</p>
<p><img loading="lazy" decoding="async" width="1070" height="509" class="wp-image-7989" src="/wp-content/uploads/2018/06/word-image-583.png" srcset="/wp-content/uploads/2018/06/word-image-583.png 1070w, /wp-content/uploads/2018/06/word-image-583-300x143.png 300w, /wp-content/uploads/2018/06/word-image-583-768x365.png 768w, /wp-content/uploads/2018/06/word-image-583-1024x487.png 1024w" sizes="(max-width: 1070px) 100vw, 1070px" /></p>
<p>3、模板upd.html回显内容</p>
<p><img loading="lazy" decoding="async" width="1271" height="587" class="wp-image-7990" src="/wp-content/uploads/2018/06/word-image-584.png" srcset="/wp-content/uploads/2018/06/word-image-584.png 1271w, /wp-content/uploads/2018/06/word-image-584-300x139.png 300w, /wp-content/uploads/2018/06/word-image-584-768x355.png 768w, /wp-content/uploads/2018/06/word-image-584-1024x473.png 1024w" sizes="(max-width: 1271px) 100vw, 1271px" /></p>
<h2>商品类型的删除</h2>
<ol>
<li>修改index.html的删除的链接地址</li>
</ol>
<p><img loading="lazy" decoding="async" width="1238" height="385" class="wp-image-7991" src="/wp-content/uploads/2018/06/word-image-585.png" srcset="/wp-content/uploads/2018/06/word-image-585.png 1238w, /wp-content/uploads/2018/06/word-image-585-300x93.png 300w, /wp-content/uploads/2018/06/word-image-585-768x239.png 768w, /wp-content/uploads/2018/06/word-image-585-1024x318.png 1024w" sizes="(max-width: 1238px) 100vw, 1238px" /></p>
<ol>
<li>在admin-type-del方法中完成删除</li>
</ol>
<p><img loading="lazy" decoding="async" width="953" height="345" class="wp-image-7992" src="/wp-content/uploads/2018/06/word-image-586.png" srcset="/wp-content/uploads/2018/06/word-image-586.png 953w, /wp-content/uploads/2018/06/word-image-586-300x109.png 300w, /wp-content/uploads/2018/06/word-image-586-768x278.png 768w" sizes="(max-width: 953px) 100vw, 953px" /></p>
<h1>三、完成商品属性的curd</h1>
<h2>1、商品属性的认识</h2>
<p>网站决定卖什么商品类型，也就决定了商品的商品属性</p>
<p>可以参考ecshop添加属性的方式:</p>
<p><img loading="lazy" decoding="async" width="960" height="427" class="wp-image-7993" src="/wp-content/uploads/2018/06/word-image-587.png" srcset="/wp-content/uploads/2018/06/word-image-587.png 960w, /wp-content/uploads/2018/06/word-image-587-300x133.png 300w, /wp-content/uploads/2018/06/word-image-587-768x342.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p>属性这里重点两种属性：唯一属性和单选属性</p>
<p>唯一属性：只能看，不能选。</p>
<p><img loading="lazy" decoding="async" width="389" height="55" class="wp-image-7994" src="/wp-content/uploads/2018/06/word-image-588.png" srcset="/wp-content/uploads/2018/06/word-image-588.png 389w, /wp-content/uploads/2018/06/word-image-588-300x42.png 300w" sizes="(max-width: 389px) 100vw, 389px" /></p>
<p>单选属性：我们购买商品的时候，可以选择的，后面添加商品的时候，不同的单选属性价格也是不一样的，如iphone6银色和iphone黑色价格是不一样的。</p>
<p><img loading="lazy" decoding="async" width="678" height="186" class="wp-image-7995" src="/wp-content/uploads/2018/06/word-image-589.png" srcset="/wp-content/uploads/2018/06/word-image-589.png 678w, /wp-content/uploads/2018/06/word-image-589-300x82.png 300w" sizes="(max-width: 678px) 100vw, 678px" /></p>
<p>②属性的值的录入方式</p>
<p><img loading="lazy" decoding="async" width="643" height="114" class="wp-image-7996" src="/wp-content/uploads/2018/06/word-image-590.png" srcset="/wp-content/uploads/2018/06/word-image-590.png 643w, /wp-content/uploads/2018/06/word-image-590-300x53.png 300w" sizes="(max-width: 643px) 100vw, 643px" /></p>
<p>手工输入：不可以输入属性值，且可选值列表是禁用状态，只能在添加商品的时候输入属性值。</p>
<p>列表选择：在可选择列表输入一些我们指定的属性值，添加商品的时候，从中选中一个属性值即可。</p>
<p>表结构：</p>
<p><img loading="lazy" decoding="async" width="916" height="162" class="wp-image-7997" src="/wp-content/uploads/2018/06/word-image-591.png" srcset="/wp-content/uploads/2018/06/word-image-591.png 916w, /wp-content/uploads/2018/06/word-image-591-300x53.png 300w, /wp-content/uploads/2018/06/word-image-591-768x136.png 768w" sizes="(max-width: 916px) 100vw, 916px" /></p>
<h2>完成商品属性的添加</h2>
<ol>
<li>在admin-attribute-add方法中完成添加属性的完成</li>
</ol>
<p><img loading="lazy" decoding="async" width="1161" height="711" class="wp-image-7998" src="/wp-content/uploads/2018/06/word-image-592.png" srcset="/wp-content/uploads/2018/06/word-image-592.png 1161w, /wp-content/uploads/2018/06/word-image-592-300x184.png 300w, /wp-content/uploads/2018/06/word-image-592-768x470.png 768w, /wp-content/uploads/2018/06/word-image-592-1024x627.png 1024w" sizes="(max-width: 1161px) 100vw, 1161px" /></p>
<p>Attribute验证器定义验证场景验证：</p>
<p><img loading="lazy" decoding="async" width="1110" height="598" class="wp-image-7999" src="/wp-content/uploads/2018/06/word-image-593.png" srcset="/wp-content/uploads/2018/06/word-image-593.png 1110w, /wp-content/uploads/2018/06/word-image-593-300x162.png 300w, /wp-content/uploads/2018/06/word-image-593-768x414.png 768w, /wp-content/uploads/2018/06/word-image-593-1024x552.png 1024w" sizes="(max-width: 1110px) 100vw, 1110px" /></p>
<p>Attribue模型如下：</p>
<p><img loading="lazy" decoding="async" width="756" height="393" class="wp-image-8000" src="/wp-content/uploads/2018/06/word-image-594.png" srcset="/wp-content/uploads/2018/06/word-image-594.png 756w, /wp-content/uploads/2018/06/word-image-594-300x156.png 300w" sizes="(max-width: 756px) 100vw, 756px" /></p>
<ol>
<li>在add.html模板中设置表单name属性值</li>
</ol>
<p><img loading="lazy" decoding="async" width="1219" height="683" class="wp-image-8001" src="/wp-content/uploads/2018/06/word-image-595.png" srcset="/wp-content/uploads/2018/06/word-image-595.png 1219w, /wp-content/uploads/2018/06/word-image-595-300x168.png 300w, /wp-content/uploads/2018/06/word-image-595-768x430.png 768w, /wp-content/uploads/2018/06/word-image-595-1024x574.png 1024w" sizes="(max-width: 1219px) 100vw, 1219px" /> <img loading="lazy" decoding="async" width="653" height="125" class="wp-image-8002" src="/wp-content/uploads/2018/06/word-image-596.png" srcset="/wp-content/uploads/2018/06/word-image-596.png 653w, /wp-content/uploads/2018/06/word-image-596-300x57.png 300w" sizes="(max-width: 653px) 100vw, 653px" /></p>
<p>注意：当选择手工输入的时候，可选择列表是禁用disabled,若是列表选择，变为可用</p>
<p>代码如下：</p>
<p><img loading="lazy" decoding="async" width="1002" height="373" class="wp-image-8003" src="/wp-content/uploads/2018/06/word-image-597.png" srcset="/wp-content/uploads/2018/06/word-image-597.png 1002w, /wp-content/uploads/2018/06/word-image-597-300x112.png 300w, /wp-content/uploads/2018/06/word-image-597-768x286.png 768w" sizes="(max-width: 1002px) 100vw, 1002px" /></p>
<h2>完成属性的列表</h2>
<ol>
<li>在admin-attribue-index方法中取出所有的属性数据，分配到模板中</li>
</ol>
<p><img loading="lazy" decoding="async" width="1026" height="476" class="wp-image-8004" src="/wp-content/uploads/2018/06/word-image-598.png" srcset="/wp-content/uploads/2018/06/word-image-598.png 1026w, /wp-content/uploads/2018/06/word-image-598-300x139.png 300w, /wp-content/uploads/2018/06/word-image-598-768x356.png 768w, /wp-content/uploads/2018/06/word-image-598-1024x475.png 1024w" sizes="(max-width: 1026px) 100vw, 1026px" /></p>
<ol>
<li>模板中遍历权限数据</li>
</ol>
<p>联表方式：</p>
<p><img loading="lazy" decoding="async" width="984" height="518" class="wp-image-8005" src="/wp-content/uploads/2018/06/word-image-599.png" srcset="/wp-content/uploads/2018/06/word-image-599.png 984w, /wp-content/uploads/2018/06/word-image-599-300x158.png 300w, /wp-content/uploads/2018/06/word-image-599-768x404.png 768w" sizes="(max-width: 984px) 100vw, 984px" /></p>
<p>不联表方式：</p>
<p><img loading="lazy" decoding="async" width="1224" height="344" class="wp-image-8006" src="/wp-content/uploads/2018/06/word-image-600.png" srcset="/wp-content/uploads/2018/06/word-image-600.png 1224w, /wp-content/uploads/2018/06/word-image-600-300x84.png 300w, /wp-content/uploads/2018/06/word-image-600-768x216.png 768w, /wp-content/uploads/2018/06/word-image-600-1024x288.png 1024w" sizes="(max-width: 1224px) 100vw, 1224px" /></p>
<h2>完成属性的编辑</h2>
<p>1、修改index.html的编辑的链接地址</p>
<p><img loading="lazy" decoding="async" width="1272" height="394" class="wp-image-8007" src="/wp-content/uploads/2018/06/word-image-601.png" srcset="/wp-content/uploads/2018/06/word-image-601.png 1272w, /wp-content/uploads/2018/06/word-image-601-300x93.png 300w, /wp-content/uploads/2018/06/word-image-601-768x238.png 768w, /wp-content/uploads/2018/06/word-image-601-1024x317.png 1024w" sizes="(max-width: 1272px) 100vw, 1272px" /></p>
<ol>
<li>在admin-attribute-upd方法中取出数据回显到模板中，并完成编辑的入库实现</li>
</ol>
<p><img loading="lazy" decoding="async" width="1065" height="702" class="wp-image-8008" src="/wp-content/uploads/2018/06/word-image-602.png" srcset="/wp-content/uploads/2018/06/word-image-602.png 1065w, /wp-content/uploads/2018/06/word-image-602-300x198.png 300w, /wp-content/uploads/2018/06/word-image-602-768x506.png 768w, /wp-content/uploads/2018/06/word-image-602-1024x675.png 1024w" sizes="(max-width: 1065px) 100vw, 1065px" /></p>
<p>3、模板中显示数据</p>
<p><img loading="lazy" decoding="async" width="1206" height="708" class="wp-image-8009" src="/wp-content/uploads/2018/06/word-image-603.png" srcset="/wp-content/uploads/2018/06/word-image-603.png 1206w, /wp-content/uploads/2018/06/word-image-603-300x176.png 300w, /wp-content/uploads/2018/06/word-image-603-768x451.png 768w, /wp-content/uploads/2018/06/word-image-603-1024x601.png 1024w" sizes="(max-width: 1206px) 100vw, 1206px" /></p>
<p>让单选框两种方式默认选中：</p>
<p>方式一：</p>
<p><img loading="lazy" decoding="async" width="991" height="305" class="wp-image-8010" src="/wp-content/uploads/2018/06/word-image-604.png" srcset="/wp-content/uploads/2018/06/word-image-604.png 991w, /wp-content/uploads/2018/06/word-image-604-300x92.png 300w, /wp-content/uploads/2018/06/word-image-604-768x236.png 768w" sizes="(max-width: 991px) 100vw, 991px" /></p>
<p>方式二：通过Jq实现，推荐写法</p>
<p><img loading="lazy" decoding="async" width="1156" height="618" class="wp-image-8011" src="/wp-content/uploads/2018/06/word-image-605.png" srcset="/wp-content/uploads/2018/06/word-image-605.png 1156w, /wp-content/uploads/2018/06/word-image-605-300x160.png 300w, /wp-content/uploads/2018/06/word-image-605-768x411.png 768w, /wp-content/uploads/2018/06/word-image-605-1024x547.png 1024w" sizes="(max-width: 1156px) 100vw, 1156px" /></p>
<h2>ajax完成商品属性的删除</h2>
<ol>
<li>给删除链接地址，绑定class和attr_id自定义属性，并且阻止默认行为</li>
</ol>
<p><img loading="lazy" decoding="async" width="1250" height="355" class="wp-image-8012" src="/wp-content/uploads/2018/06/word-image-606.png" srcset="/wp-content/uploads/2018/06/word-image-606.png 1250w, /wp-content/uploads/2018/06/word-image-606-300x85.png 300w, /wp-content/uploads/2018/06/word-image-606-768x218.png 768w, /wp-content/uploads/2018/06/word-image-606-1024x291.png 1024w" sizes="(max-width: 1250px) 100vw, 1250px" /></p>
<ol>
<li>给class=delAttr绑定单击事件，使用ajax进行删除</li>
</ol>
<p><img loading="lazy" decoding="async" width="1173" height="468" class="wp-image-8013" src="/wp-content/uploads/2018/06/word-image-607.png" srcset="/wp-content/uploads/2018/06/word-image-607.png 1173w, /wp-content/uploads/2018/06/word-image-607-300x120.png 300w, /wp-content/uploads/2018/06/word-image-607-768x306.png 768w, /wp-content/uploads/2018/06/word-image-607-1024x409.png 1024w" sizes="(max-width: 1173px) 100vw, 1173px" /></p>
<ol>
<li>在admin-attribute-ajaxDel方法中完成删除的实现</li>
</ol>
<h1>四、完成商品分类的curd</h1>
<h2>1、分析分类表结构</h2>
<p>表字段结构如下：</p>
<p><img loading="lazy" decoding="async" width="760" height="153" class="wp-image-8014" src="/wp-content/uploads/2018/06/word-image-608.png" srcset="/wp-content/uploads/2018/06/word-image-608.png 760w, /wp-content/uploads/2018/06/word-image-608-300x60.png 300w" sizes="(max-width: 760px) 100vw, 760px" /></p>
<h2>完成商品分类的添加</h2>
<p>找当前分类的祖先分类：传递当前分类的pid ,谁的cat_id等于我的pid就找到我的祖先。</p>
<p>找当前分类的子孙分类：传递当前分类的cat_id ,谁的pid等于我的cat_id就找到我的子孙</p>
<ol>
<li>在admin-category-add方法中完成添加分类的完成</li>
</ol>
<p><img loading="lazy" decoding="async" width="949" height="536" class="wp-image-8015" src="/wp-content/uploads/2018/06/word-image-609.png" srcset="/wp-content/uploads/2018/06/word-image-609.png 949w, /wp-content/uploads/2018/06/word-image-609-300x169.png 300w, /wp-content/uploads/2018/06/word-image-609-768x434.png 768w" sizes="(max-width: 949px) 100vw, 949px" /></p>
<p>验证器：</p>
<p><img loading="lazy" decoding="async" width="730" height="546" class="wp-image-8016" src="/wp-content/uploads/2018/06/word-image-610.png" srcset="/wp-content/uploads/2018/06/word-image-610.png 730w, /wp-content/uploads/2018/06/word-image-610-300x224.png 300w" sizes="(max-width: 730px) 100vw, 730px" /></p>
<p>模型：</p>
<p><img loading="lazy" decoding="async" width="1109" height="639" class="wp-image-8017" src="/wp-content/uploads/2018/06/word-image-611.png" srcset="/wp-content/uploads/2018/06/word-image-611.png 1109w, /wp-content/uploads/2018/06/word-image-611-300x173.png 300w, /wp-content/uploads/2018/06/word-image-611-768x443.png 768w, /wp-content/uploads/2018/06/word-image-611-1024x590.png 1024w" sizes="(max-width: 1109px) 100vw, 1109px" /></p>
<p>2、在add.html模板中设置表单name属性值</p>
<p><img loading="lazy" decoding="async" width="1196" height="591" class="wp-image-8018" src="/wp-content/uploads/2018/06/word-image-612.png" srcset="/wp-content/uploads/2018/06/word-image-612.png 1196w, /wp-content/uploads/2018/06/word-image-612-300x148.png 300w, /wp-content/uploads/2018/06/word-image-612-768x380.png 768w, /wp-content/uploads/2018/06/word-image-612-1024x506.png 1024w" sizes="(max-width: 1196px) 100vw, 1196px" /></p>
<h2>完成商品分类的列表</h2>
<ol>
<li>在admin-category-index方法中取出所有的分类数据，分配到模板中</li>
</ol>
<p><img loading="lazy" decoding="async" width="785" height="352" class="wp-image-8019" src="/wp-content/uploads/2018/06/word-image-613.png" srcset="/wp-content/uploads/2018/06/word-image-613.png 785w, /wp-content/uploads/2018/06/word-image-613-300x135.png 300w, /wp-content/uploads/2018/06/word-image-613-768x344.png 768w" sizes="(max-width: 785px) 100vw, 785px" /></p>
<p>同时为了不用联表，把分类的无限级分类的以cat_id作为下标</p>
<p><img loading="lazy" decoding="async" width="1126" height="457" class="wp-image-8020" src="/wp-content/uploads/2018/06/word-image-614.png" srcset="/wp-content/uploads/2018/06/word-image-614.png 1126w, /wp-content/uploads/2018/06/word-image-614-300x122.png 300w, /wp-content/uploads/2018/06/word-image-614-768x312.png 768w, /wp-content/uploads/2018/06/word-image-614-1024x416.png 1024w" sizes="(max-width: 1126px) 100vw, 1126px" /></p>
<p>2、模板index.html中遍历分类数据</p>
<p><img loading="lazy" decoding="async" width="1279" height="572" class="wp-image-8021" src="/wp-content/uploads/2018/06/word-image-615.png" srcset="/wp-content/uploads/2018/06/word-image-615.png 1279w, /wp-content/uploads/2018/06/word-image-615-300x134.png 300w, /wp-content/uploads/2018/06/word-image-615-768x343.png 768w, /wp-content/uploads/2018/06/word-image-615-1024x458.png 1024w" sizes="(max-width: 1279px) 100vw, 1279px" /></p>
<p>效果：</p>
<p><img loading="lazy" decoding="async" width="1156" height="241" class="wp-image-8022" src="/wp-content/uploads/2018/06/word-image-616.png" srcset="/wp-content/uploads/2018/06/word-image-616.png 1156w, /wp-content/uploads/2018/06/word-image-616-300x63.png 300w, /wp-content/uploads/2018/06/word-image-616-768x160.png 768w, /wp-content/uploads/2018/06/word-image-616-1024x213.png 1024w" sizes="(max-width: 1156px) 100vw, 1156px" /></p>
<h2>完成商品分类的编辑</h2>
<ol>
<li>修改index.html的编辑的链接地址</li>
</ol>
<p><img loading="lazy" decoding="async" width="1258" height="353" class="wp-image-8023" src="/wp-content/uploads/2018/06/word-image-617.png" srcset="/wp-content/uploads/2018/06/word-image-617.png 1258w, /wp-content/uploads/2018/06/word-image-617-300x84.png 300w, /wp-content/uploads/2018/06/word-image-617-768x216.png 768w, /wp-content/uploads/2018/06/word-image-617-1024x287.png 1024w" sizes="(max-width: 1258px) 100vw, 1258px" /></p>
<p>2、在admin-category-upd方法中完取出当前分类的数据回显到模板中，并完成编辑入库的实现</p>
<p><img loading="lazy" decoding="async" width="1000" height="644" class="wp-image-8024" src="/wp-content/uploads/2018/06/word-image-618.png" srcset="/wp-content/uploads/2018/06/word-image-618.png 1000w, /wp-content/uploads/2018/06/word-image-618-300x193.png 300w, /wp-content/uploads/2018/06/word-image-618-768x495.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<h2>5、【作业】完成商品分类的删除</h2>
<p>自行完成</p>
<p>CategoryController:</p>
<p><img loading="lazy" decoding="async" width="577" height="326" class="wp-image-8025" src="/wp-content/uploads/2018/06/word-image-619.png" srcset="/wp-content/uploads/2018/06/word-image-619.png 577w, /wp-content/uploads/2018/06/word-image-619-300x169.png 300w" sizes="(max-width: 577px) 100vw, 577px" /></p>
<p>Html:</p>
<p><img loading="lazy" decoding="async" width="883" height="122" class="wp-image-8026" src="/wp-content/uploads/2018/06/word-image-620.png" srcset="/wp-content/uploads/2018/06/word-image-620.png 883w, /wp-content/uploads/2018/06/word-image-620-300x41.png 300w, /wp-content/uploads/2018/06/word-image-620-768x106.png 768w" sizes="(max-width: 883px) 100vw, 883px" /> <img loading="lazy" decoding="async" width="734" height="403" class="wp-image-8027" src="/wp-content/uploads/2018/06/word-image-621.png" srcset="/wp-content/uploads/2018/06/word-image-621.png 734w, /wp-content/uploads/2018/06/word-image-621-300x165.png 300w" sizes="(max-width: 734px) 100vw, 734px" /></p>
<h1>六、完成商品类型列表中属性的查看</h1>
<h1>七、完成商品的添加</h1>
<h2>商品的认识</h2>
<p>商品=产品+商品属性，即同一个产品，但是商品属性不同，就不是同一个商品。</p>
<p>如：iphone6s黑色 和iphone6s银色</p>
<h2>商品添加所需的数据表</h2>
<p>当在后台添加一个商品的时候，商品相关数据需要入库到以下两个表：</p>
<p>商品表sh_goods和商品属性表sh_goods_attr</p>
<p><img loading="lazy" decoding="async" width="159" height="40" class="wp-image-8028" src="/wp-content/uploads/2018/06/word-image-622.png" /></p>
<p>商品的基本信息数据存储在sh_goods表中，商品属性数据存储在sh_goods_attr中</p>
<p>商品表sh_goods表结构：</p>
<p>商品属性表sh_goods_attr表结构：</p>
<h2>完成商品基本信息的入库</h2>
<h3>（1）展示添加商品模板</h3>
<h3>基本信息入库操作</h3>
<h2>4、添加商品的多图片上传</h2>
<h3>（1）思路分析</h3>
<p>实现思路：可以参考ecshop开源商城：</p>
<p><img loading="lazy" decoding="async" width="985" height="188" class="wp-image-8029" src="/wp-content/uploads/2018/06/word-image-623.png" srcset="/wp-content/uploads/2018/06/word-image-623.png 985w, /wp-content/uploads/2018/06/word-image-623-300x57.png 300w, /wp-content/uploads/2018/06/word-image-623-768x147.png 768w" sizes="(max-width: 985px) 100vw, 985px" /></p>
<p>①构建布局：</p>
<p>每个文件上传域名其实可以看做是一个li标签，其中包含a标签和input上传文件域</p>
<p>如下结构：</p>
<p>&lt;li&gt; &lt;a href=’javascript:;’ &gt;[+]&lt;/a&gt;&lt;input type=’file’/&gt; &lt;/li&gt;</p>
<p>&lt;li&gt; &lt;a href=’javascript:;’ &gt;[-]&lt;/a&gt;&lt;input type=’file’/&gt; &lt;/li&gt;</p>
<p>②怎么实现图片前的[+][-]加减功能？</p>
<p>思路：</p>
<ol>
<li>给li中的a标签绑定单击事件，获取当前单击元素的内容</li>
<li>判断内容，含两种情况[+]、[-]</li>
</ol>
<p>若是[+]: 则获取当前元素的父元素（即li），克隆一份，在把内部的a标签的[+]变成[-]。</p>
<p>若是[-]: 则获取当前元素的父元素（即li），并移除。</p>
<h3>多图片上传加减特效</h3>
<h3>实现多图片的上传</h3>
<h3>（4）生成多图片的缩略图</h3>
<p>生成缩略图的步骤：</p>
<ul>
<li>Image打开源图片 $image = \Think\Image::open(源图片);</li>
<li>进行缩放处理 $image -&gt; thumb(宽度，高度，类型)</li>
<li>把缩放好的图片保存到服务器上 $image -&gt; save(小图路径名);</li>
</ul>
<h1>八、完成商品的属性添加</h1>
<h2>1、分析商品动态属性的生成</h2>
<p>添加一个商品，其商品属性可能有多个。</p>
<p>即商品表sh_goods的一条记录对应商品属性表sh_goods_attr的多条记录，属于一对多关系。</p>
<p>问题：怎么给商品设置商品属性？</p>
<p>这里可以参考ecshop的方案，当添加商品的,必须先选择一个商品类型，在通过ajax动态获取商品类型的属性，再给商品设置这些属性值。</p>
<p>如在ecshop后台添加商品的时候，选择手机类型，动态生成的属性框如下：</p>
<p><img loading="lazy" decoding="async" width="1084" height="312" class="wp-image-8030" src="/wp-content/uploads/2018/06/word-image-624.png" srcset="/wp-content/uploads/2018/06/word-image-624.png 1084w, /wp-content/uploads/2018/06/word-image-624-300x86.png 300w, /wp-content/uploads/2018/06/word-image-624-768x221.png 768w, /wp-content/uploads/2018/06/word-image-624-1024x295.png 1024w" sizes="(max-width: 1084px) 100vw, 1084px" /></p>
<p>从上面添加商品属性可以看出，动态生成商品属性的时候，共有四种组合情况。</p>
<p>其实就是属性类型和属性值录入方式的互相组合：</p>
<p>①唯一属性+手工输入</p>
<p>②唯一属性+列表选择</p>
<p>③单选属性+手工输入</p>
<p>④单选属性+列表选择</p>
<p>其实可以把上面每个动态生成的属性信息看作是被包含在一个li标签中。</p>
<p>分析四种组合情况生成动态属性的特点如下：</p>
<p>元素从左到右分析：</p>
<ul>
<li>单选属性属性名称前有个[+]或[-]号，可以进行加减，而唯一属性则没有</li>
<li>属性名称</li>
<li>属性值录入方式为手工输入，则对应属性值的输入方式的是一个输入框(&lt;input type=’text’/&gt;)，而属性值录入方式为列表选择的时候则对应属性值的输入方式的是一个select下拉框。</li>
<li>单选属性可以输入价格，而唯一属性则没有</li>
</ul>
<h2>完成商品的动态属性生成</h2>
<h2>完成商品动态属性的入库</h2>
<p>分析：</p>
<p>把单选属性值和单选属性价格通过属性attr_id归为同一组，方便后续获取对应属性的价格和值。</p>
<p>单选属性值： name=goodsAttrValue[attr_id][]</p>
<p>单选属性值价格： name=goodsAttrValue[attr_id][]</p>
<p>因为单选属性用户可以点击[+]号会生成多个，所以多个单选属性值和价格name的值后面都必须加上中括号[]。</p>
<p>由于唯一属性只能选择一个值，所以name后不需要加[]</p>
<h1>九、商品列表展示</h1>
<h1>十、使用ajax+layer弹出层查看商品详情</h1>
]]></content:encoded>
					
					<wfw:commentRss>/%e5%90%8e%e5%8f%b0%e6%a1%86%e6%9e%b6/7899.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
