laravel框架后台内容管理系统项目搭建心得分享

laravel框架后台内容管理系统项目搭建心得分享

前期准备 

一、后台用户登录

1、创建用户表

2、显示登录页面

3、Ajax交互

 4、验证用户登录

5、用户退出

二、后台首页 

1、后台页面布局

2、显示后台首页

3、判断登录状态

三、栏目管理 

1、创建栏目表

2、添加栏目

3、显示栏目列表

4、编辑栏目

5、删除栏目

 四、内容管理

1、创建内容表

2、添加内容

3、上传图片

4、显示内容列表

5、编辑内容

6、删除内容

 五、广告位管理

 1、创建广告位表

 2、添加广告位

 3、显示、编辑、删除广告位列表

六、广告内容管理

1、创建广告内容表

2、添加、显示、编辑、删除广告

七、 总结

1、学习laravel的难点

2、学习laravel收获到了什么

3、内容管理系统项目心得总结


Larvel框架可以开发各种不同类型的项目,内容管理系统( Contet Mangement Sstem, CMS )是一种比较典型的项目,常见的网站类型(如门户、新闻、博客、文章等)都可以利用CMS进行:搭建。CMS用于对信息进行分类管理,将信息有序、及时地呈现在用户面前,满足人们发布信息、获取信息的需求,保证信息的共享更加快捷和方便。本章将讲解如何使用Laravel框架开发内容管理系统。


(1)本项目分为前台和后台。前台的功能包括用户登录与注册、内容列表、内容详细页、广告展示、评论和热门内容等。

(2)后台在未登录的状态下会自动跳转至登录页面。输入用户名“admin”、密码“123456”和验证码后,单击“登录”按钮,即可进行登录。

(3)登录后,页面顶部右侧显示了当前登录的用户名“admin”和“退出”按钮,单击“退出”按钮即可退出后台系统。

(4)后台页面的左侧有一个菜单栏,用户可以在菜单栏中选择一个菜单项进行操作。

项目中需要使用到的技术点包括文件上传、分页和会话技术。整个项目开发基于实现功能的步骤来完成,先实现后台开发,提供数据支持,再完成前台的数据展示。

前期准备 

(1)在C:\web\apache2.4\htdocs\cms目录下打开终端,执行如下命令,安装Laravel。

composer create-project --prefer-dist laravel/laravel ./ 5.8.*

或下载地址:https://getcomposer.org/download/

(2)Laravel安装完成后,在Apache的conf\extra\httpd-vhosts.conf配置文件中创建一个虚拟主机。然后,编辑Windows系统的hosts文件,添加一条解析记录“lhm.com”。

(3)在本书的配套源代码包中,将内容管理系统的前台和后台的静态资源复制到项目对应的目录下。

(4)登录MySQL服务器,创建数据库cms,将cms作为内容管理系统的数据库。

(5)打开项目,在config\database.php数据库配置文件中,将数据库名称修改为lhm。

(6)在.env文件中配置正确的数据库配置信息。完成上述步骤后,即可在项目中访问数据库。

目录作用
App包含了应用的核心代码,此外你为应用编写的代码绝大多数也会放到这里;
Bootstrap用于框架的启动和自动载入配置;
Config包含了应用所有的配置文件
Database包含了数据迁移及填充文件
PublicPublic
Resourcesresources目录包含了视图文件及原生资源文件
Routes包含了应用的所有路由定义
Storage存放编译后的模板、session文件、缓存文件、日志文件等;
Tests自动化测试文件
Vendor存放通过Composer加载的依赖

一、后台用户登录

1、创建用户表

(1)在命令行中执行如下命令创建迁移文件,具体命令如下:

php artisan make:migration create_admin_user_table

 (2)执行完上述命令后,会在database\migrations目录下生成文件名称为时间前缀_create_admin_user_table.php的文件 。

(3)在迁移文件的up()方法中添加表结构信息,具体代码如下:

 public function up()
    {
        Schema::create('admin_user', function (Blueprint $table) {
            $table->increments('id')->comment('主键');
            $table->string('username', 32)->comment('用户名')->unique();
            $table->string('password', 32)->comment('密码');
            $table->char('salt', 32)->comment('密码salt');
            $table->timestamps();
 
        });
    }

(5)上述命令会执行迁移文件中的up()方法,来完成数据表的创建。

(6)创建填充文件,具体命令如下:

php artisan migrate

(7)执行完上述命令后,会在database\seeds目录下生成对应的迁移文件,文件名为AdminuserTableSeeder.php。

(8)在填充文件的run()方法中编写填充代码:

public function run()
{
    $salt = md5(uniqid(microtime(), true));
    $password = md5(md5('123456') . $salt);
    DB::table('admin_user')->insert([
        [
            'id' => 1,
            'username' => 'admin',
            'password' => $password,
            'salt' => $salt
        ],
    ]);
}

(9)执行填充文件命令:

php artisan db:seed --class=AdminuserTableSeeder

(10)数据库创建成功后,创建用户模型:

php artisan make:model Admin

(11)打开app\Admin.php,在模型中指定要操作的表名,具体代码如下:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Admin extends Model
{
    protected $table = 'admin_user';
    public $fillable = ['username', 'password'];
}

2、显示登录页面

(1)创建User控制器。

php artisan make:controller Admin/UserController

(2)打开UserController.php,创建login()方法。

public function login(){
    return view('admin/login');
}

(3)在routes\web.php文件中添加路由规则。

Route::get('/admin/login','Admin\UserController@login');

(4)在resources\views目录下创建admin目录,该目录用于存放后台相关的模板文件。然后在admin目录中创建login.blade.php文件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 引入静态文件 -->
    <title>登录</title>
</head>
<body class="login">
<div class="container">
<!-- 登录表单 -->
</div>
</body>
</html>

(5)在login.blade.php文件中引入静态文件。

    <link rel="stylesheet" href="{{asset('admin')}}/common/twitter-bootstrap/4.4.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="{{asset('admin')}}/common/font-awesome-4.2.0/css/font-awesome.min.css">
    <link rel="stylesheet" href="{{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.css">
    <link rel="stylesheet" href="{{asset('admin')}}/css/main.css">
    <script src="{{asset('admin')}}/common/jquery/1.12.4/jquery.min.js"></script>
    <script src="{{asset('admin')}}/common/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
    <script src="{{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.js"></script>
    <script src="{{asset('admin')}}/js/main.js"></script>

(6)在login.blade.php文件中定义登录表单。

<form action="" method="post" class="j-login">
    <h1>后台管理系统</h1>
    <div class="form-group">
      <input type="text" name="username" class="form-control" placeholder="用户名" required>
    </div>
    <div class="form-group">
      <input type="password" name="password" class="form-control" placeholder="密码" required>
    </div>
    <div class="form-group">
      <input type="text" name="captcha" class="form-control" placeholder="验证码" required>
    </div>
    <!-- 验证码 -->
    <div class="form-group">
      {{csrf_field()}}
      <input type="submit" class="btn btn-lg btn-block btn-success" value="登录">
    </div>
</form>
 

(7)使用Composer载入mews/captcha验证码库。

composer require mews/captcha=3.0

(8)创建验证码的配置文件。

php artisan vendor:publish

(9)编辑config\captcha.php文件,将字符个数改为4。

'default' => [
        'length' => 4, //字符个数
        'width' => 120, //图片宽度
        'height' => 36, //图片高度
        'quality' => 90, //图片质量
        'math' => false, //数学计算
    ],

(10)在config\app.php文件中将验证码服务注册到服务容器中。

'providers' => [
     ...(原有代码)
     Mews\Captcha\CaptchaServiceProvider::class,
     ...(原有代码)
]

(11)在config\app.php文件中给验证码服务注册别名。

'aliases' => [
     ...(原有代码)
    'Captcha' =>Mews\Captcha\Facades\Captcha::class,
]

(12)在登录表单中添加验证码。

<div class="form-group">
      <div class="login-captcha"><img src="{{ captcha_src() }}" alt="captcha"></div>
 </div>

(13)实现单击验证码图片后更换验证码的功能,在模板中编写JavaScript 代码。

 <script>
    $('.login-captcha img').click(function() {
    $(this).attr('src', '{{ captcha_src()}}' + '?_=' + Math.random());
  });
</script> 

(14)运行效果图如下:

3、Ajax交互

Ajax交互封装的开发思路:

① 将Ajax操作的代码封装到一个对象中,该对象可以随意命名,这里命名为main。

② 通过main.ajax()方法发送Ajax请求,该方法有3个参数,第1个参数可以是对象或字符串,如果是对象,则用于传递给$.ajax(),如果是字符串,则表示请求地址;第2个参数表示当服务器返回成功结果时执行的回调函数;第3个参数表示当服务器返回失败结果时执行的回调函数。

③ 当开始发送Ajax请求时,在页面中显示加载提示,并在收到服务器响应后,隐藏加载提示。

④ 当Ajax请求失败,或服务器响应错误信息时,通过toastr对象将错误信息显示在页面中。

在分析了要完成的主要功能后,下面开始进行代码编写:

① 打开public\admin\js\main.js文件,编写window.main对象。

② 在main对象中编写ajaxPost()方法,用于发送POST请求。

在main.js中编写ajaxForm()方法,用于将表单改为Ajax提交方式

ajax知识拓展:

Ajax (Asynchronous JavaScript and XML) 是一种使用已有的标准技术,通过 JavaScript 实现浏览器与服务器之间异步数据传输的方法。它的主要特点是在不刷新整个页面的情况下,可以与服务器交换数据并更新部分页面内容,从而提升用户体验。

Ajax 技术的核心是 XMLHttpRequest 对象,通过该对象可以实现异步请求数据和更新部分页面内容。当用户与 Web 应用程序交互时,JavaScript 会发送异步请求到服务器端,服务器响应请求并返回需要的数据,JavaScript 再根据返回的数据更新页面。

Ajax 技术的应用非常广泛,如实现自动补全、实时搜索等功能,提高了用户的体验感和操作效率。同时,Ajax 还可以用于异步上传文件、处理表单数据等场景。

 4、验证用户登录

(1)设置<form>标签的action属性设置表单的提交地址,给登录表单的action属性添加属性值,指定表单的提交地址为“{{ url('admin/check') }}”,表示UserController的check()方法。

(2)编写代码完成验证用户登录。

① 在routes\web.php文件中添加路由规则。

//登录验证
Route::post('/admin/check','Admin\UserController@check');

② 在UserController.php中创建check()方法。

public function check(Request $request)
    {
        //声明自动验证规则
        $rule = [
            'username' => 'required',
            'password' => 'required|min:6',
            'captcha' => 'required|captcha'
        ];
        // 声明自动验证规则对应的提示信息(验证失败返回信息)
        $message = [
            'username.required' => '用户名不能为空',
            'password.required' => '密码不能为空',
            'password.min'     => '密码最少为6位',
            'captcha.required' => '验证码不能为空',
            'captcha.captcha' => '验证码有误'
        ];
        //进行自动验证,验证表单提交数据
        $validator = Validator::make($request->all(), $rule, $message);
        // 输出验证结果并返回给浏览器
        if ($validator->fails()) {   //验证失败fails()方法
            foreach ($validator->getMessageBag()->toArray() as $v) {
                $msg = $v[0];
            }
            return response()->json(['code' => 0, 'msg' => $msg]);
        }
        // 获取用户输入的用户名、密码信息,以及数据表中用户名、密码信息
        $username = $request->get('username');
        $password = $request->get('password');
        $theUser = Admin::where('username',$username)->first();
        // 对用户输入的密码与数据库中的密码进行比较,如果密码正确则登录成功,并将用户信息保存在session中
        // 跳转至后台首页,如果登录失败,则显示“登录失败”
        if($theUser->password == md5(md5($password). $theUser->salt))
        {
            Session::put('user', ['id'=>$theUser->id,'name'=>$username]);
            return response()->json(['code' => 1, 'msg' => '登录成功']);
        }else{
            return response()->json(['code' => 0, 'msg' => '登录失败']);
        }
    }

③ 导入Admin模型、Session、Validator的命名空间。

use App\Admin;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;

(3)通过浏览器访问,输入小于6 位的密码,页面会出现“密码最少为6 位”的错误提示;如果提交正确的用户名(admin)和密码(123456),页面中会出现“登录成功”的提示。

5、用户退出

(1)在User控制器中添加logout()方法。

 public function logout(){
        if(request()->session()->has('user')){
            request()->session()->pull('user',session('user'));
        }
        return redirect('/admin/login');
    }

(2)在routes\web.php文件中添加路由规则。

//用户退出
Route::get('/admin/logout','Admin\UserController@logout');

通过浏览器访问,在确保用户已经登录以后,访问http://cms.test/admin/logout,浏览器会自动跳转到登录页面,说明当前用户已经成功退出。

二、后台首页 

在用户登录成功后,就会进入到后台首页。网站的后台首页一般会显示一些欢迎信息、系统信息、统计数据等系统信息。本节将实现上述功能。

1、后台页面布局

在后台管理系统的页面中,一般都会包含顶部、菜单和内容区域这3 个部分,可将后台页面的顶部和左侧菜单提取出来,作为公共文件供其他模板调用,在 resources\views\admin下创建 layouts目录,此目录将作为公共文件的存放目录。开发步骤如下。

(1)在layouts目录下创建admin.blade.php文件。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--引入静态文件-->
  <title>@yield('title')</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light main-navbar">
  <a class="navbar-brand" href="#">后台管理系统</a>
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="nav ml-auto main-nav-right">
      <li>
        <a href="#" class="j-layout-pwd">
          <i class="fa fa-user fa-fw"></i>{{session()->get('user.name')}}
        </a>
      </li>
      <li>
        <a href="{{url('admin/logout')}}">
          <i class="fa fa-power-off fa-fw"></i>退出
        </a>
      </li>
    </ul>
  </div>
</nav>
<!-- 后台页面的首页部分 -->
<div class="main-container">
  <div class="main-content">
    <div>@yield('main')</div>
  </div>
</div>
</body>
</html>

(2)在页面中引入静态资源。

  <link rel="stylesheet" href="{{asset('admin')}}/common/twitter-bootstrap/4.4.1/css/bootstrap.min.css">
  <link rel="stylesheet" href="{{asset('admin')}}/common/font-awesome-4.2.0/css/font-awesome.min.css">
  <link rel="stylesheet" href="{{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.css">
  <link rel="stylesheet" href="{{asset('admin')}}/css/main.css">
  <script src="{{asset('admin')}}/common/jquery/1.12.4/jquery.min.js"></script>
  <script src="{{asset('admin')}}/common/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
  <script src="{{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.js"></script>
  <script src="{{asset('admin')}}/js/main.js"></script>

(3)在页面中定义左侧导航栏。

<div class="main-sidebar">
      <ul class="nav flex-column main-menu">
      
</div>

(4)添加首页菜单。

        <li class="">
          <a href="{{url('admin/index')}}" class="active">
            <i class="fa fa-home fa-fw"></i>首页
          </a>
        </li>

(5)添加栏目菜单。

        <li class="main-sidebar-collapse">  <!-- 被收起的双层项 -->
          <a href="#" class="main-sidebar-collapse-btn">   <!-- 链接用于展开或收起子菜单 -->
              <i class="fa fa-list-alt fa-fw"></i>栏目
              <span class="fa main-sidebar-arrow"></span>  <!-- 双层项的右侧小箭头 -->
          </a>
          <ul class="nav">
            <!-- 设置子菜单 -->
            <li>
              <a href="#" data-name="addcategory">
              <i class="fa fa-list fa-fw"></i>添加</a>
            </li>
            <li>
              <a href="#" data-name="category">
                <i class="fa fa-table fa-fw"></i>列表</a>
            </li>
          </ul>
        </li>

(6)添加内容菜单。

        <li class="main-sidebar-collapse">
          <a href="#" class="main-sidebar-collapse-btn">
            <i class="fa fa-list-alt fa-fw"></i>内容
            <span class="fa main-sidebar-arrow"></span>
          </a>
          <ul class="nav">
            <li>
              <a href="#" data-name="addcontent">
              <i class="fa fa-list fa-fw"></i>添加</a>
            </li>
            <li>
              <a href="#" data-name="content">
                <i class="fa fa-table fa-fw"></i>列表</a>
            </li>
          </ul>
        </li>

(7)添加广告菜单。

         <li class="main-sidebar-collapse">
          <a href="#" class="main-sidebar-collapse-btn">
            <i class="fa fa-cog fa-fw"></i>广告
            <span class="fa main-sidebar-arrow"></span>
          </a>
          <ul class="nav">
            <li>
              <a href="#" data-name="adv">
                <i class="fa fa-list fa-fw"></i>广告位</a>
            </li>
            <li>
              <a href="#" data-name="advcontent">
                <i class="fa fa-list-alt fa-fw"></i>广告内容</a>
           </li>
          </ul>
        </li>

(8)添加消息提示模板。

@if(!empty(session('message')))
  <div class="alert alert-success" role="alert"
    style="text-align:center;margin:0 auto;width: 400px">
      {{session('message')}}
  </div>
@endif
@if(!empty(session('tip')))
  <div class="alert alert-warning" role="alert"
  style="text-align:center;margin:0 auto;width: 400px">
    {{session('tip')}}
  </div>
@endif

(9)在<body>标签结束前的位置添加<script>标签,控制消息模板的显示时间。

<script>
  // setInterval(myFunction,myTimeLapse),每隔myTimeLapse(毫秒)执行一次myFunction()函数
  setInterval(function(){
    $('.alert').remove();
  },3000);
</script>

(10)修改public\admin\js\main.js文件,编写layout()方法。

 layout: function() {
      $('.main-sidebar-collapse-btn').click(function() {
        $(this).parent().find('.nav').slideToggle(200);
        $(this).parent().toggleClass('main-sidebar-collapse').siblings().
            addClass('main-sidebar-collapse').find('.nav').slideUp(200);
        return false;
      });
    },

(11)在main.js中增加menuActive()方法,用于将指定菜单项设为选中效果。

在<script>标签中调用layout()方法。

menuActive: function(name) {
      var menu = $('.main-menu');
      menu.find('a').removeClass('active');
      menu.find('a[data-name=\'' + name + '\']').addClass('active');
      menu.find('a[data-name=\'' + name + '\']').parent().parent().show();
    }

2、显示后台首页

(1)公共文件创建完成后,接下来创建后台首页admin\index.blade.php。

@extends('admin/layouts/admin')
@section('title', '后台首页')
@section('main')
  <div>
    <div class="main-title">
      <h2>首页</h2>
    </div>
    <div class="main-section">
      <div class="card">
        <div class="card-header">服务器信息</div>
        <ul class="list-group list-group-flush">
          <li class="list-group-item">系统环境:{{ $server_version }}</li>
          <li class="list-group-item">Laravel版本:{{ $laravel_version }}</li>
          <li class="list-group-item">MySQL版本:{{ $mysql_version }}</li>
          <li class="list-group-item">服务器时间:{{ $server_time }}</li>
          <li class="list-group-item">文件上传限制:{{ $upload_max_filesize }}</li>
          <li class="list-group-item">脚本执行时限:{{ $max_execution_time }}</li>
        </ul>
      </div>
    </div>
  </div>
@endsection

(2)创建Index控制器。

php artisan make:controller Admin\IndexController

(3)在Index控制器中添加index()方法。

    public function index(Request $request){
        $data = [
            'server_version' => $request->server('SERVER_SOFTWARE'),
            'laravel_version' => app()::VERSION,
            'mysql_version' => $this->getMySQLVer(),
            'server_time' => date('Y-m-d H:i:s', time()),
            'upload_max_filesize' => ini_get('file_uploads') ?
                ini_get('upload_max_filesize') : '已禁用',
            'max_execution_time' => ini_get('max_execution_time') . '秒'
        ];
        return view('admin\index', $data);
    }

(4)在上述代码中,第6行代码调用getMySQLVer()方法获取MySQL的版本,创建getMySQLVer()方法。

private function getMySQLVer()
    {
        $res = DB::select('SELECT VERSION() AS ver');
        return $res[0]->ver ?? '未知';
    }

(5)在getMySQLVer()方法中,使用DB类执行SQL,获取MySQL的版本,导入DB类的命名空间。

(6)在routes\web.php文件中添加路由规则,通过浏览器访问后台首页。

Route::get('/admin/index', 'Admin\IndexController@index');

(7)通过浏览器访问后台首页,其效果如下图:

3、判断登录状态

在用户登录成功以后,需要通过Session 来记住登录状态,并在下次请求中判断用户有没有登录。由于后台是给内部人员使用的,除了登录功能外,其他功能都必须在用户登录后才能使用。为了便于判断用户的登录状态,利用中间件来实现。在明确了需求后,下面开始完成判断登录状态的逻辑功能。

(1)创建Admin中间件,用于验证用户是否登录。

(2)打开app\Http\Middleware\Admin.php,添加验证用户登录的代码。

 public function handle($request, Closure $next)
    {
        if (request()->session()->has('user')) {
            $user = request()->session()->get('user');
            view()->share('user', $user);
        } else {
            return redirect('/admin/login');
        }
        return $next($request);
    }

(3)在app\Http\Kernel.php文件中注册路由中间件。

protected $routeMiddleware = [
    ...(原有代码)
    'Admin' => \App\Http\Middleware\Admin::class,
];

(4)修改首页的路由规则,为后台首页添加用户验证。

Route::get('/admin/index', 'Admin\IndexController@index')->middleware(['Admin']);

通过浏览器直接访问后台首页时,如果处于未登录状态,就会自动跳转至登录页面。

三、栏目管理 

在内容管理系统中,栏目用于对内容进行分类,如生活类、咨询类、编程类。对内容进行分类,可以使用户更高效地找到需要的信息。本节将会讲解如何完成栏目管理功能的开发,实现栏目的查询、添加、修改和删除功能。

1、创建栏目表

(1)创建栏目表迁移文件,然后打开栏目表的迁移文件,在该文件的up()方法中添加表结构信息。

 public function up()
    {
        
        Schema::create('category', function (Blueprint $table) {
            $table->increments('id')->comment('主键');
            $table->integer('pid')->comment('父类id') ->default('0');
            $table->string('name', 32)->comment('分类名称');
            $table->integer('sort')->comment('排序值') ->default('0');
            $table->timestamps();
        });
 
 
    }

(2)栏目表创建完成后,为了在项目中操作栏目表,下面创建栏目表对应的模型文件。

php artisan make:model Category

(3)打开app\Category.php文件,配置模型。

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Category extends Model
{
    protected $table = "category";
    public $fillable = ['pid', 'name', 'sort'];
}

 2、添加栏目

栏目分为两级,即父栏目和子栏目。父栏目下包含多个子栏目,子栏目不能选择其他子栏目作为自己的父栏目。

(1)创建Category控制器。

(2)在控制器中添加add()方法,用于实现添加栏目的功能。

<?php
 
namespace App\Http\Controllers\Admin;
 
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Category;
 
class CategoryController extends Controller
{
    public function add(){
        $category = Category::where('pid', 0)->get();
        return view('admin.category.add', ['category' => $category] );
    }
}

(3)创建admin\category\add.blade.php视图文件。

@extends('admin/layouts/admin')
@section('title', ' 添加栏目')
@section('main')
<div class="main-title"><h2>添加栏目</h2></div>
<div class="main-section">
  <div style="width:543px">
    <!-- 添加栏目表单 -->
    <form method="post" action="{{ url('/category/save') }}">
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">序号</label>
        <div class="col-sm-10">
          <input type="number" name="sort" class="form-control" value="0" style="width:80px;">
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">上级栏目</label>
        <div class="col-sm-10">
          <select name="pid" class="form-control" style="width:200px;">
            <option value="0">---</option>
            @foreach ($category as $v)
              <option value="{{ $v->id }}"> {{ $v->name }}</option>
            @endforeach
          </select>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">名称</label>
        <div class="col-sm-10">
          <input type="text" name="name" class="form-control" style="width:200px;">
        </div>
      </div>
      <div class="form-group row">
        <div class="col-sm-10">
          {{csrf_field()}}
          <button type="submit" class="btn btn-primary mr-2">提交表单</button>
          <a href="{{url('category')}}" class="btn btn-secondary">返回列表</a>
        </div>
      </div>
    </form>
  </div>
</div>
<script>
  main.menuActive('addcategory');
</script>
@endsection

(4)在上一步代码中的第7行的位置添加表单。

(5)在routes\web.php文件中添加路由规则。

// 栏目
Route::prefix('category')->namespace('Admin')->middleware(['Admin'])->group(function () {
    Route::get('add', 'CategoryController@add');
});

(6)修改布局文件admin.blade.php,为添加栏目的导航添加链接。

<a href="{{ url('category/add') }}" data-name="addcategory"><i class="fa fa-list fa-fw"></i>添加</a>

(7)在Category控制器中编写save()方法,用于接收添加栏目的表单数据。

 public function save(Request $request){
        $data = $request->all();
        $this->validate($request,[
            'name'=>'required|unique:category'.$rule,
        ],[
            'name.required'=>'栏目名称不能为空',
            'name.unique'=>'栏目名称不能重复'
        ]);
        $re = Category::create($data);
        if($re){
            return redirect('category')->with('message','添加成功');
        }else{
            return redirect('category/add')->with('tip','添加失败');
        }
    }

(8)在routes\web.php文件中栏目的路由组中添加路由规则。

Route::post('save', 'CategoryController@save');

(9)通过浏览器访问,添加栏目后,查看数据表中是否有新增的栏目数据

3、显示栏目列表

(1)在Category控制器中创建index()方法。

    public function index(){
        $category = $this->getTreeListCheckLeaf($data);
        return view('admin.category.index', ['category' => $category]);
    }

(2)在Category模型中添加getTreeList()方法、getTreeListCheckLeaf()方法和treeList()方法。

 public function getTreeListCheckLeaf($data, $name = 'isLeaf')
    {
        $data = $this->treeList($data);
        foreach ($data as $k => $v) {
            foreach ($data as $vv) {
                $data[$k][$name] = true;
                if ($v['id'] === $vv['pid']) {
                    $data[$k][$name] = false;
                    break;
                }
            }
        }
        return $data;
    }
 
    public function treeList($data, $pid = 0, $level = 0, &$tree = [])
    {
        foreach ($data as $v) {
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $tree[] = $v;
                $this->treeList($data, $v['id'], $level + 1, $tree);
            }
        }
        return $tree;
    }

(3)创建视图文件index.blade.php。

@extends('admin/layouts/admin')
@section('title', '栏目列表')
@section('main')
<div class="main-title"><h2>栏目管理</h2></div>
<div class="main-section form-inline">
  <a href="{{ url('category/add') }}" class="btn btn-success">+ 新增</a>
</div>
<div class="main-section">
  <form method="post" action="" class="j-form">
    <table class="table table-striped table-bordered table-hover">
      <thead>
      <tr>
        <th width="75">序号</th><th>名称</th><th width="100">操作</th>
      </tr>
      </thead>
      <tbody>
      <!-- 栏目列表 -->
      @foreach($category)
        <tr class="j-pid-{{ $v['pid'] }}"
          @if($v['level'])style="display:none"@endif>
          <td><input type="text" class="form-control j-sort" maxlength="5" value="{{$v['sort']}}" data-name="sort[{{$v['id']}}]" style="height:25px;font-size:12px;padding:0 5px;"></td>
          <td>
            @if($v['level'])
              <small class="text-muted">├──</small> {{$v['name']}}
            @else
              <a href="#" class="j-toggle" data-id="{{$v['id']}}">
                @if(!$v['isLeaf'])
                  <i class="fa fa-plus-square-o fa-minus-square-o fa-fw"></i>
                @endif
                {{$v['name']}}
              </a>
            @endif
          </td>
          <td>
            <a href="{{ url('category/edit', ['id' => $v['id']]) }}" style="margin-right:5px;">编辑</a>
            <a href="{{ url('category/delete', ['id' => $v['id']]) }}" class="j-del text-danger">删除</a>
          </td>
        </tr>
      @endforeach
      @if(empty($category))
        <tr><td colspan="4" class="text-center">还没有添加栏目</td></tr>
      @endif
      </tbody>
    </table>
    {{csrf_field()}}
    <input type="submit" value="改变排序" class="btn btn-primary">
  </form>
</div>
<script>
  main.menuActive('category');
  $('.j-toggle').click(function() {
    var id = $(this).attr('data-id');
    $(this).find('i').toggleClass('fa-plus-square-o');
    $('.j-pid-' + id).toggle();
    return false;
  });
  $('.j-sort').change(function() {
    $(this).attr('name', $(this).attr('data-name'));
  });
  $('.j-del').click(function() {
    if (confirm('您确定要删除此项?')) {
      var data = { _token: '{{ csrf_token() }}' };
      main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
        location.reload();
      });
    }
    return false;
  });
</script>
@endsection

(4)添加栏目列表。

(5)在页面中添加JavaScript代码,实现单击栏目展开该栏目下的子栏目的功能。

(6)在routes\web.php文件中栏目的路由组中添加栏目列表的路由规则。

(7)修改admin.blade.php,为列表菜单项添加链接。

    Route::get('', 'CategoryController@index');

(8)在栏目列表页中,为了实现修改栏目的排序,需要设置栏目列表页中表单的提交地址。

  <form method="post" action="{{ url('category/sort')}}" class="j-form">

(9)在routes\web.php文件中栏目的路由组中添加排序的路由规则。

    Route::post('sort', 'CategoryController@sort');

(10)添加JavaScript代码,修改排序值后,为input输入框设置name属性。

(11)在Category控制器中添加sort()方法。

通过浏览器访问,观察栏目排序功能是否正确执行。

public function sort(Request $request){
        $sort = $request->input('sort');
        foreach ($sort as $k => $v) {
            Category::where('id', (int)$k)->update(['sort' => (int)$v]);
        }
        return redirect('category')->with('message','改变排序成功');
    }

 

4、编辑栏目

(1)在列表页单击每条栏目对应的“编辑”按钮,即可对此栏目进行编辑。下面在列表页中为“编辑”按钮添加链接。

<a href="{{ url('category/edit', ['id' => $v['id']]) }}" style="margin-right:5px;">编辑</a>

(2)在routes\web.php文件中栏目的路由组中添加编辑栏目的路由规则。

    Route::get('edit/{id}', 'CategoryController@edit');

(3)在Category控制器中添加edit()方法。

public function edit($id){
        $data = [];
        if ($id) {
            if (!$data = Category::find($id)) {
                return back()->with('tip', '记录不存在。');
            }
        }
        $category = Category::where('pid', 0)->get();
        return view('admin.category.edit', ['id'=>$id, 'data'=>$data, 'category' => $category]);
    }

(4)创建视图文件edit.blade.php。

@extends('admin/layouts/admin')
@section('title', '栏目列表')
@section('main')
<div class="main-title"><h2>编辑分类</h2></div>
<div class="main-section">
  <div style="width:543px">
    <!-- 编辑表单 -->
    <form method="post" action="{{ url('/category/save') }}">
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">序号</label>
        <div class="col-sm-10">
          <input type="number" name="sort" class="form-control" value="{{$data->sort}}" style="width:80px;">
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">上级分类</label>
        <div class="col-sm-10">
          <select name="pid" class="form-control" style="width:200px;">
            <option value="0">---</option>
            @foreach($category as $v)
              <option value="{{ $v->id }}" @if($data['pid'] == $v['id']) selected @endif> {{ $v->name }}</option>
            @endforeach
          </select>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">名称</label>
        <div class="col-sm-10">
          <input type="text" name="name" class="form-control" value="{{$data->name}}" style="width:200px;">
        </div>
      </div>
      <div class="form-group row">
        <div class="col-sm-10">
          {{csrf_field()}}
          <input type="hidden" name="id" value="{{$id}}">
          <button type="submit" class="btn btn-primary mr-2">提交表单</button>
          <a href="{{url('category')}}" class="btn btn-secondary">返回列表</a>
          {{--<a href="{{url('category')}}">--}}
            {{--<button class="btn btn-secondary">返回列表</button>--}}
          {{--</a>--}}
        </div>
      </div>
    </form>
  </div>
</div>
<script>
  main.menuActive('category');
</script>
@endsection

(5)添加编辑栏目的表单。

(6)修改save()方法,根据栏目id更新栏目内容。

通过浏览器访问,观察编辑栏目功能是否正确执行。

public function save(Request $request){
        $data = $request->all();
        $rule = isset($data['id']) ? ',name,'.$data['id'] : '';
        $this->validate($request,[
            'name'=>'required|unique:category'.$rule,
        ],[
            'name.required'=>'栏目名称不能为空',
            'name.unique'=>'栏目名称不能重复'
        ]);
        if(isset($data['id'])){
            $id = $data['id'];
            unset($data['id']);
            unset($data['_token']);
            $res = Category::where('id',$id)->update($data);
            $type = $res ? "message" : "tip";
            $message = $res ? "修改成功" : "修改失败";
            return redirect('category')->with($type, $message);
        }
        $re = Category::create($data);
        if($re){
            return redirect('category')->with('message','添加成功');
        }else{
            return redirect('category/add')->with('tip','添加失败');
        }
    }

 

5、删除栏目

(1)在列表页中为“删除”按钮添加链接。

(2)在Category控制器中添加delete()方法。

public function delete($id){
        if (!$category = Category::find($id)) {
            return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
        }
        $category->delete();
        return response()->json(['code' => 1, 'msg' => '删除成功' ]);
    }

(3)在routes\web.php文件的栏目路由组中添加删除栏目的路由规则。

    Route::post('delete/{id}', 'CategoryController@delete');

(4)通过浏览器访问,观察删除栏目功能是否成功实现。

 四、内容管理

 在内容管理系统中可以管理的内容有很多,如文章、图片、商品、电影、音乐等,本节主要实现内容管理功能。内容管理功能的开发思路与栏目管理功能类似,但内容管理功能还需要支持上传文件功能,例如,用户可以上传封面图用于在前台中展示。此外,还应考虑到将来内容会越来越多,需要提供分页查询功能,以便于用户进行浏览。

1、创建内容表

(1)创建内容表对应的迁移文件后,在迁移文件的up()方法中添加表结构信息。内容表的字段有id、cid(栏目id)、title(标题)、content(内容)、image(图片)和status(状态)等字段。

 public function up()
    {
        Schema::create('content', function (Blueprint $table) {
            $table->increments('id')->comment('主键');
            $table->integer('cid')->comment('栏目id')->default(0);
            $table->string('title', 255)->comment('标题');
            $table->text('content', 255)->comment('内容');
            $table->char('image', 255)->comment('图片');
            $table->tinyInteger('status')->comment('状态默认1推荐2')->default(1);
            $table->timestamps();
        });
 
    }

(2)创建内容表对应的模型文件app\Content.php。

php artisan make:model Content

2、添加内容

(1)创建Content 控制器。

(2)在控制器中添加add( )方法,用于实现添加内容的功能。

 public function add()
    {
        $data = Category::orderBy('sort', 'asc')->get()->toArray();
        $cate = new CategoryController();
        $category = $cate->getTreeListCheckLeaf($data);
        return view('admin.content.add', ['category' => $category]);
    }
 
    public function save(Request $request)
    {
        $data = $request->all();
        $this->validate($request,[
            'cid'=>'required',
            'title'=>'required'
        ],[
            'cid.require'=>'分类不能为空',
            'title.require'=>'标题不能为空'
        ]);
        if(isset($data['id'])){
            $id = $data['id'];
            unset($data['id']);
            unset($data['_token']);
            $res = Content::where('id',$id)->update($data);
            $type = $res ? "message" : "tip";
            $message = $res ? "修改成功" : "修改失败";
            return redirect('content')->with($type, $message);
        }
 
        $re = Content::create($data);
        if($re){
            return redirect('content')->with('message','添加成功');
        }else{
            return redirect('content/add')->with('tip','添加失败');
        }
    }

(3)在控制器中导入Category 模型的命名空间。

(4)创建resources\views\admin\content\add.blade.php视图文件。

@extends('admin/layouts/admin')
@section('title', '添加内容')
@section('main')
<div class="main-title"><h2>添加内容</h2></div>
<div class="main-section">
  <div style="width:80%">
    <!-- 添加内容表单 -->
    <form method="post" action="{{ url('/content/save') }}" class="j-form">
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">所属分类</label>
        <div class="col-sm-10">
          <select name="cid" class="form-control" style="width:200px;">
            <!-- 分类下拉列表 -->
            @foreach($category as $v)
              @if($v['level'])
                <option value="{{$v['id']}}">
                  <small class="text-muted">├──</small>{{$v['name']}}
                </option>
              @else
                <option value="{{$v['id']}}"> {{$v['name']}}</option>
              @endif
            @endforeach
          </select>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">标题</label>
        <div class="col-sm-10">
          <input type="text" name="title" class="form-control" style="width:200px;">
        </div>
      </div>
      <!-- 上传图片按钮 -->
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">图片</label>
        <div class="col-sm-10">
          <input type="file" id="file1" name="image" value="上传图片" multiple="true">
        </div>
        <div class="col-sm-10 offset-sm-2">
          <div class="upload-img-box" id="uploadImg"></div>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">简介</label>
        <div class="col-sm-10">
          <!-- <textarea class="j-goods-content" name="content" style="height:500px"></textarea> -->
          <script type="text/plain" class="j-goods-content" name="content" style="height:500px"></script>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2 col-form-label">状态</label>
        <div class="col-sm-10">
          <div class="form-check form-check-inline" style="height:38px">
            <input class="form-check-input" id="inlineRadio1" type="radio" name="status" value="1" checked>
            <label class="form-check-label" for="inlineRadio1">默认</label>
          </div>
          <div class="form-check form-check-inline" style="height:38px">
            <input class="form-check-input" id="inlineRadio2" type="radio" name="status" value="2">
            <label class="form-check-label" for="inlineRadio2">推荐</label>
          </div>
        </div>
      </div>
      <div class="form-group row">
        <div class="col-sm-10">
          {{csrf_field()}}
          <button type="submit" class="btn btn-primary mr-2">提交表单</button>
          <a href="{{url('content')}}" class="btn btn-secondary">返回列表</a>
        </div>
      </div>
    </form>
  </div>
</div>
<link href="{{asset('admin')}}/common/uploader/uploadifive.css" rel="stylesheet" />
<script src="{{asset('admin')}}/common/uploader/jquery.uploadifive.js"></script>
<script src="{{asset('admin')}}/common/editor/ueditor1.4.3.3/ueditor.config.js"></script>
<script src="{{asset('admin')}}/common/editor/ueditor1.4.3.3/ueditor.all.min.js"></script>
<script src="{{asset('admin')}}/common/editor/main.editor.js"></script>
<script>
    main.menuActive('addcontent');
    $(function() {
      $('#file1').uploadifive({
        'auto'            : true,
        'fileObjName'     : 'image',
        'fileType'        : 'image',
        'buttonText'      : '上传图片',
        'formData'        : { '_token' : "{{ csrf_token() }}" },
        'method'          : 'post',
        'queueID'         : 'uploadImg',
        'removeCompleted' : true,
        'uploadScript'    : '{{ url('content/upload')}}',
        'onUploadComplete': uploadPicture_icon
      });
    });
    function uploadPicture_icon(file, data) {
      var obj = $.parseJSON(data);
      var src = '';
      if (obj.code) {
        filename = obj.data.filename;
        path = obj.data.path;
        $('.upload-img-box').empty();
        $('.upload-img-box').html(
          '<div class="upload-pre-item" style="max-height:100%;"><img src="' + path + '" style="width:100px;height:100px"/> <input type="hidden" name="image" value="'+filename+'" class="icon_banner"/></div>'
        );
      } else {
        alert(data.info);
      }
    }
    main.editor($('.j-goods-content'), 'goods_edit', function(opt) {
      opt.UEDITOR_HOME_URL = '{{asset('admin')}}/common/editor/ueditor1.4.3.3/';
    }, function(editor) {
      $('.j-form').submit(function() {
        editor.sync();
      });
    });
</script>
@endsection

(5)在视图中添加内容表单。

(6)在视图中添加栏目下拉列表。

(7)在Content 控制器中添加save()方法保存添加的内容。

(8)在控制器中引入Content的命名空间。

(9)在Routes\web.php中添加内容管理的路由组。

Route::prefix('content')->namespace('Admin')->middleware(['Admin'])->group(function () {
 
    Route::get('add', 'ContentController@add');
    Route::post('save', 'ContentController@save');
});

(10)修改admin.blade.php,为添加内容的菜单项添加链接。

<a href="{{ url('content/add') }}" data-name="addcontent">
              <i class="fa fa-list fa-fw"></i>添加</a>

(11)通过浏览器访问,观察添加内容功能是否正确执行。

 

 3、上传图片

(1)在添加内容的视图中添加上传图片的按钮。

<div class="form-group row">
        <label class="col-sm-2 col-form-label">图片</label>
        <div class="col-sm-10">
          <input type="file" id="file1" name="image" value="上传图片" multiple="true">
        </div>
        <div class="col-sm-10 offset-sm-2">
          <div class="upload-img-box" id="uploadImg"></div>
        </div>
      </div>

(2)在视图中引入上传文件所需的样式和JavaScript代码。

<link href="{{asset('admin')}}/common/uploader/uploadifive.css" rel="stylesheet" />
<script src="{{asset('admin')}}/common/uploader/jquery.uploadifive.js"></script>
<script src="{{asset('admin')}}/common/uploader/jquery.uploadifive.min.js"></script>

(3)在<script>标签中配置“上传图片”按钮。

(4)在Content控制器中编写upload()方法。

 public function upload(Request $request)
    {
        if ($request->hasFile('image')) {
            $image = $request->file('image');
            if ($image->isValid()) {
                $name = md5(microtime(true)) . '.' . $image->extension();
                $image->move('static/upload', $name);
                $path = '/static/upload/' . $name;
                $returndata  = array(
                    'filename' => $name,
                    'path' => $path
                );
                $result = [
                    'code' => 1,
                    'msg'  => '上传成功',
                    'time' => time(),
                    'data' => $returndata,
                ];
                return response()->json($result);
            }
            return $image->getErrorMessage();
        }
        return '文件上传失败';
    }

(5)在routes\web.php文件中内容的路由组中添加上传图片的路由规则。

(6)通过浏览器访问测试。在添加内容时,单击“上传图片”按钮,选择一张图片进行上传。

(7)由于图片文件通常都比较小,上传速度很快,为了更好地看到上传进度的变化,在浏览器的开发者工具中切换到“Network”面板。

(8)更改网速后,选择图片进行上传,就可以看到图片的上传进度。

(9)当上传完图片后,就会显示已经上传的图片。

4、显示内容列表

(1)在Content控制器中编写index()方法。

public function index($id = 0)
    {
        $data = Category::orderBy('sort', 'asc')->get()->toArray();
        $cate = new CategoryController();
        $category = $cate->getTreeListCheckLeaf($data);
        $content = Content::get();
        if ($id) {
            $content = Content::where('cid', $id)->get();
        }
        return view('admin.content.index', ['category' => $category, 'content' => $content, 'cid' => $id]);
    }

(2)在展示内容时,需要显示内容对应的栏目,因此在Content模型中添加关联模型。

public function category()
    {
        return $this->belongsTo('App\Category', 'cid', 'id');
    }

(3)创建resources\views\admin\content\index.blade.php文件。

@extends('admin/layouts/admin')
@section('title', '内容列表')
@section('main')
  <div class="main-title"><h2>内容管理</h2></div>
  <div class="main-section form-inline">
    <a href="{{ url('content/add') }}" class="btn btn-success">+ 新增</a>
    <!-- 此处编写分类下拉菜单 -->
    <select class="j-select form-control" style="min-width:120px;margin-left:8px">
      <option value="{{ url('content', ['id' => 0]) }}">所有分类</option>
      @foreach($category as $v)
        @if($v['level'])
        <option value="{{ url('content', ['d' => $v['id']]) }}" data-id="{{$v['id']}}">
          <small class="text-muted">--</small> {{$v['name']}}
        </option>
        @else
        <option value="{{ url('content', ['id' => $v['id']]) }}" data-id="{{$v['id']}}">
          {{$v['name']}}
        </option>
        @endif
      @endforeach
    </select>
  </div>
  <div class="main-section">
    <form method="post" action="{{ url('category/sort')}}" class="j-form">
      <table class="table table-striped table-bordered table-hover">
        <thead>
        <tr>
          <th width="75">序号</th><th>分类</th><th>图片</th><th>标题</th>
          <th>状态</th><th>创建时间</th><th width="100">操作</th>
        </tr>
        </thead>
        <tbody>
        @foreach($content as $v)
          <!-- 此处编写内容列表代码 -->
          <tr class="j-pid-{{ $v->pid }}" @if($v->level)style="display:none"@endif>
            <td>{{ $v->id }}</td>
            <td>{{ $v->category->name}}</td>
            <td><img @if($v->image) src="/static/upload/{{ $v->image}}" @else src="{{asset('admin')}}/img/noimg.png" @endif width="50" height="50"></td>
            <td>{{ $v->title }}</td>
            <td>@if($v->status==1) 默认  @else 推荐 @endif</td>
            <td>{{ $v->created_at }}</td>
            <td><a href="{{ url('content/edit', ['id' => $v->id ]) }}" style="margin-right:5px;">编辑</a>
              <a href="{{ url('content/delete', ['id' => $v->id ]) }}" class="j-del text-danger">删除</a>
            </td>
          </tr>
        @endforeach
        @if(empty($content))
          <tr><td colspan="7" class="text-center">还没有添加内容</td></tr>
        @endif
        </tbody>
      </table>
      {{csrf_field()}}
    </form>
  </div>
  <script>
    main.menuActive('content');
    $('.j-select').change(function() {
      location.href = $(this).val();
    });
    $('option[data-id=' + {{$cid}} + ']').attr('selected', true);
    $('.j-del').click(function() {
      if (confirm('您确定要删除此项?')) {
        var data = { _token: '{{ csrf_token() }}' };
        main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
          location.reload();
        });
      }
      return false;
    });
  </script>
@endsection

(4)在foreach中输出内容列表。

(5)编写栏目下拉列表。

(6)在页面的<script>标签中编写代码实现下拉列表的切换。

(7)在routes\web.php中添加内容列表页的路由。

    Route::get('{id?}', 'ContentController@index');

(8)修改admin.blade.php,为内容列表添加链接。通过浏览器访问,查看内容列表页面效果

5、编辑内容

(1)在内容列表页面单击每条内容对应的“编辑”按钮,即可对此条内容进行编辑。

<a href="{{ url('content/edit', ['id' => $v->id ]) }}" style="margin-right:5px;">编辑</a>

(2)在Content控制器中添加edit()方法。

 public function edit(Request $request)
    {
        $id = $request->id;
        $data = Category::orderBy('sort', 'asc')->get()->toArray();
        $cate = new CategoryController();
        $category = $cate->getTreeListCheckLeaf($data);
        $content = Content::find($id);
        return view('admin.content.edit', ['category' => $category, 'content' => $content]);
    }

(3)修改save()方法,接收栏目id。

(4)在routes\web.php文件中添加内容列表页的路由。

    Route::get('edit/{id}', 'ContentController@edit');

(5)通过浏览器访问,观察编辑内容功能是否能正确执行。

 

6、删除内容

(1)在内容列表页面单击每条内容对应的“删除”按钮,即可删除此条内容,下面在内容列表页面中为“删除”按钮添加链接。

(2)在routes\web.php文件中添加删除内容的路由。

    Route::post('delete/{id}', 'ContentController@delete');

(3)在列表页中找到<script>标签。

(4)在Content控制器中添加delete()方法。

 public function delete($id)
    {
        if (!$content = Content::find($id)) {
            return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
        }
        $content->delete();
        return response()->json(['code' => 1, 'msg' => '删除成功' ]);
    }

(5)通过浏览器访问,观察删除内容功能是否成功实现。

 五、广告位管理

在网站中常会看到一些广告,这些广告都是在网站的广告位上显示的,目前,在网站建站需求中,添加广告信息已经是重要的需求,因此CMS提供了广告管理模块,广告管理模块主要包括广告位管理和广告内容管理,本节讲解广告位管理的实现。

 1、创建广告位表

(1)创建广告位表对应的迁移文件后,在迁移文件的up()方法中添加表结构信息。广告位表的字段有id 和name(广告位名称)等字段。

 public function up()
    {
        Schema::create('adv', function (Blueprint $table) {
            $table->increments('id')->comment('主键');
            $table->string('name', 32)->comment('广告位名称');
            $table->timestamps();
        });
    }

(2)创建广告位表对应的模型文件app\Adv.php。

php artisan make:model Adv

2、添加广告位

(1)创建Adv控制器。

php artisan make:controller Admin\AdvController

(2)在控制器中添加add()方法,用于实现添加广告位的功能。

  public function add($id = 0){
        $data = [];
        if($id > 0){
            $data = Adv::find($id);
        }
        return view('admin.adv.add', ['data' => $data]);
    }
 
    public function save(Request $request){
        $data = $request->all();
 
        $this->validate($request,[
            'name'=>'required'
        ],[
            'name.require'=>'名称不能为空'
        ]);
        if(isset($data['id'])){
            $id = $data['id'];
            unset($data['id']);
            unset($data['_token']);
            $res = Adv::where('id',$id)->update($data);
            $type = $res ? "message" : "tip";
            $message = $res ? "修改成功" : "修改失败";
            return redirect('adv')->with($type, $message);
        }
 
        $re = Adv::create($data);
        if($re){
            return redirect('adv')->with('message','添加成功');
        }else{
            return redirect('adv/add')->with('tip','添加失败');
        }
    }

(3)创建resources\views\admin\adv\add.blade.php视图文件。

(4)在Adv控制器中添加save()方法保存添加的广告位。

(5)在控制器中引入Adv的命名空间。

use App\Adv;

(6)在routes\web.php中添加广告位管理的路由组。

//广告
Route::prefix('adv')->namespace('Admin')->middleware(['Admin'])->group(function () {
    Route::get('add/{id?}', 'AdvController@add');
    Route::post('save', 'AdvController@save');
});

(7)通过浏览器访问,观察添加广告位功能是否能正确执行。

 3、显示、编辑、删除广告位列表

(1)修改admin.blade.php,为广告位菜单项添加链接。

<a href="{{url('adv')}}" data-name="adv">
    <i class="fa fa-list fa-fw"></i>广告位</a>

(2)在routes\web.php 中添加广告位列表的路由。

    Route::get('', 'AdvController@index');
    route::post('delete/{id}','AdvController@delete');

(3)在Adv控制器中编写index()和delete()方法。

public function index(){
        $adv = Adv::all();
        return view('admin.adv.index', ['adv' => $adv]);
    }
 
 public function delete($id){
 
        if (!$content = Adv::find($id)) {
            return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
        }
        if(Advcontent::where('advid', '=', $id)->exists()){
            return response()->json(['code' => 0, 'msg' => '该广告位下有广告记录,请先删除广告内容。' ]);
        }
        $content->delete();
 
        return response()->json(['code' => 1, 'msg' => '删除成功' ]);
    }

(4)创建index.blade.php文件。

@extends('admin/layouts/admin')
@section('title', '广告位列表')
@section('main')
<div class="main-title"><h2>广告位管理</h2></div>
<div class="main-section form-inline">
  <a href="{{ url('adv/add') }}" class="btn btn-success">+ 新增</a>
</div>
<div class="main-section">
  <table class="table table-striped table-bordered table-hover">
    <thead>
      <tr>
        <th width="75">序号</th><th>广告位名称</th><th width="100">操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- 广告位列表-->
      @foreach($adv as $v)
      <tr class="j-pid-{{ $v['pid'] }}">
        <td><input type="text" value="{{$v->id}}" class="form-control j-sort" maxlength="5" style="height:25px;font-size:12px;padding:0 5px;"></td>
        <td>{{$v->name}}</td>
        <td>
          <a href="{{ url('adv/add', ['id' => $v->id]) }}" style="margin-right:5px;">编辑</a>
          <a href="{{ url('adv/delete', ['id' => $v->id]) }}" class="j-del text-danger">删除</a>
        </td>
      </tr>
      @endforeach
      @if(empty($adv))
      <tr><td colspan="4" class="text-center">还没有添加广告位</td></tr>
      @endif
    </tbody>
  </table>
</div>
<script>
main.menuActive('adv');
$('.j-del').click(function() {
    if (confirm('您确定要删除此项?')) {
    var data = { _token: '{{ csrf_token() }}' };
    main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
        location.reload();
    });
    }
    return false;
});
</script>
@endsection

(5)在视图中输出广告位列表。

(6)通过浏览器访问,查看广告列列表的页面效果。

六、广告内容管理

在内容管理系统中,添加广告内容时需要选择广告所属的广告位,从而设置广告的显示位置。在前面章节中已经介绍了广告位模块的开发,下面对广告内容管理模块的功能进行详细讲解。

1、创建广告内容表

(1)创建广告内容表的迁移文件后,在迁移文件的 up()方法中添加表结构信息。

public function up()
    {
        Schema::create('adcontent', function (Blueprint $table) {
            $table->increments('id')->comment('主键');
            $table->integer('advid')->comment('广告位id');
            $table->integer('path')->comment('图片路径');
            $table->timestamps();
        });
 
    }

(2)创建内容表对应的模型文件。

php artisan make:model Advcontent

(3)打开自动创建的app\Advcontent.php模型文件,对模型进行配置。

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Advcontent extends Model
{
    protected $table = "adcontent";
    public $fillable = ['advid','path'];
}

2、添加、显示、编辑、删除广告

(1)创建Advcontent控制器,具体代码如下:

php artisan make:controller Admin\AdvcontentController

(2)在控制器中添加add()方法用于实现添加广告的功能,添加save()方法用于保存广告内容,添加upload()方法用于保存上传的广告图片,添加index()方法,添加delete()方法,具体代码如下: 

public function add($id = 0){
        $data = [];
        if($id > 0){
            $data = Advcontent::find($id);
            if($data['path']){
                $data['path'] = explode("|", $data['path']);
            }else{
                $data['path'] = [];
            }
        }
        $position = Adv::all();
        return view('admin.advcontent.add', ['data' => $data, 'position' => $position]);
    }
 
    public function save(Request $request){
        $data = $request->all();
        $path = '';
        foreach($data['path'] as $v){
            $path .= $v . "|";
        }
        $data['path'] = substr($path,0,-1);
        if(isset($data['id'])){
            $id = $data['id'];
            unset($data['id']);
            unset($data['_token']);
            $res = Advcontent::where('id',$id)->update($data);
            $type = $res ? "message" : "tip";
            $message = $res ? "修改成功" : "修改失败";
            return redirect('advcontent')->with($type, $message);
        }
 
        $re = Advcontent::create($data);
        if($re){
            return redirect('advcontent')->with('message','添加成功');
        }else{
            return redirect('advcontent/add')->with('tip','添加失败');
        }
    }
 
    public function upload(Request $request){
        if ($request->hasFile('image')) {
            $image = $request->file('image');
            if ($image->isValid()) {
                $name = md5(microtime(true)) . '.' . $image->extension();
                $image->move('static/upload', $name);
                $path = '/static/upload/' . $name;
                $returndata  = array(
                    'filename' => $name,
                    'path' => $path
                );
                $result = [
                    'code' => 1,
                    'msg'  => '上传成功',
                    'time' => time(),
                    'data' => $returndata,
                ];
 
                return response()->json($result);
            }
            return $image->getErrorMessage();
        }
        return '文件上传失败';
 
    }
 
    public function index(){
        $adv = Advcontent::all();
        foreach($adv as $v){
            if($v['path']){
                $v['path'] = explode("|", $v['path']);
            }else{
                $v['path'] = [];
            }
        }
        return view('admin.advcontent.index', ['adv' => $adv]);
    }
 
    public function delete($id){
        if (!$content = Advcontent::find($id)) {
            return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
        }
        $content->delete();
        return response()->json(['code' => 1, 'msg' => '删除成功' ]);
    }

(3)在控制器中引入广告位的命名空间,具体代码如下: 

use App\Advcontent;
use App\Adv;

(4)创建resources\views\admin\advcontent\add.blade.php视图文件,具体代码如下: 

@extends('admin/layouts/admin')
@section('title', '添加广告')
@section('main')
<div class="main-title"><h2><div class="main-title"><h2>@if(!empty($data))编辑@else添加@endif广告</h2></div>
<div class="main-section">
  <div style="width:543px">
    <form method="post" action="{{ url('/advcontent/save') }}">
      <div class="form-group row">
        <label class="col-sm-3 col-form-label">选择广告位</label>
        <div class="col-sm-9">
          <!-- 广告位列表 -->
          <select name="advid" class="form-control" style="width:200px;">
            @foreach ($position as $v)
            <option value="{{ $v->id }}" @if(isset($data->advposid) && $data->advposid == $v->id) selected @endif>
              {{ $v->name }}
            </option>
            @endforeach
          </select>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-3 col-form-label">上传图片</label>
        <div class="col-sm-9">
          <input type="file" id="file1" name="path" value="上传图片">
        </div>
        <div class="col-sm-9 offset-sm-3">
          <div class="upload-img-box" id="uploadImg">
            @if(isset($data->path))
            <div class="upload-pre-item" style="max-height:100%;">
                @foreach ($data->path as $val)
                <img src="/static/upload/{{$val}}"
                    style="width:100px;height:100px"/>
                <input type="hidden" name="path[]" value="{{$val}}"
                        class="icon_banner"/>
                @endforeach
            </div>
            @endif
          </div>
        </div>
      </div>
      <div class="form-group row">
        <div class="col-sm-9">
          {{csrf_field()}}
          @if(isset($data['id'])) <input type="hidden" name="id" value="{{$data->id}}"> @endif
          <button type="submit" class="btn btn-primary mr-2">提交表单</button>
          <a href="{{ url('advcontent') }}" class="btn btn-secondary">返回列表</a>
        </div>
      </div>
    </form>
  </div>
</div>
<link href="{{asset('admin')}}/common/uploader/uploadifive.css" rel="stylesheet" />
<script src="{{asset('admin')}}/common/uploader/jquery.uploadifive.js"></script>
<script>
main.menuActive('advcontent');
$(function(){
  $('#file1').uploadifive({
    'auto'       : true,
    'fileObjName'    : 'image',
    'fileType'     : 'image',
    'buttonText'     : '上传图片',
    'formData'     : { '_token' : "{{ csrf_token() }}" },
    'method'       : 'post',
    'queueID'      : 'uploadImg',
    'removeCompleted'  : true,
    'uploadScript'   : '{{ url('advcontent/upload')}}',
    'onUploadComplete' : uploadPicture_icon
  });
});
function uploadPicture_icon(file, data) {
  var obj = $.parseJSON(data);
  var src = '';
  if (obj.code) {
    filename = obj.data.filename;
    path = obj.data.path;
    if ($('.upload-pre-item').length > 0) {
        $('.upload-pre-item').append(
            '<img src="' + path + '" style="width:100px;height:100px"/> <input type="hidden" name="path[]" value="'+filename+'" class="icon_banner"/>'
        );
    } else {
      $('.upload-img-box').append(
        '<div class="upload-pre-item" style="max-height:100%;"><img src="' + path + '" style="width:100px;height:100px"/> <input type="hidden" name="path[]" value="'+filename+'" class="icon_banner"/></div>'
      );
    }
  } else {
    alert(data.info);
  }
}
</script>
@endsection

(5)创建index.php文件,具体代码如下: 

@extends('admin/layouts/admin')
@section('title', '广告内容管理')
@section('main')
<div class="main-title"><h2>广告内容管理</h2></div>
<div class="main-section form-inline">
  <a href="{{ url('advcontent/add') }}" class="btn btn-success">+ 新增</a>
</div>
<div class="main-section">
  <table class="table table-striped table-bordered table-hover">
    <thead>
    <tr>
      <th width="75">序号</th><th>广告位名称</th><th>广告图片</th><th width="100">操作</th>
    </tr>
    </thead>
    <tbody>
    <!-- 广告位列表 -->
    @foreach($adv as $v)
      <tr class="j-pid-{{ $v['pid'] }}">
        <td><input type="text" value="{{$v->id}}" class="form-control j-sort" maxlength="5" style="height:25px;font-size:12px;padding:0 5px;"></td>
        <td>{{$v->position->name}}</td>
        <td>
          @foreach($v->path as $val)
            <img src="/static/upload/{{$val}}" style="height:40px;width: 50px">
          @endforeach
        </td>
        <td><a href="{{ url('advcontent/add', ['id' => $v->id]) }}" style="margin-right:5px;">编辑</a>
          <a href="{{ url('advcontent/delete', ['id' => $v->id]) }}" class="j-del text-danger">删除</a>
        </td>
      </tr>
    @endforeach
    @if(empty($adv))
      <tr><td colspan="4" class="text-center">还没有添加广告内容</td></tr>
    @endif
    </tbody>
  </table>
</div>
<script>
  main.menuActive('advcontent');
  $('.j-del').click(function() {
    if (confirm('您确定要删除此项?')) {
      var data = { _token: '{{ csrf_token() }}' };
      main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
        location.reload();
      });
    }
    return false;
  });
</script>
@endsection

(6)在routes\web.php中添加广告位管理的路由组,具体代码如下: 

//广告列表
Route::prefix('advcontent')->namespace('Admin')->middleware(['Admin'])->group(function () {
    Route::get('add/{id?}', 'AdvcontentController@add');
    Route::post('save', 'AdvcontentController@save');
    Route::post('upload','AdvcontentController@upload');
    Route::get('', 'AdvcontentController@index');
    route::post('delete/{id}','AdvcontentController@delete');
});

(7)修改app\Advcontent.php,设置关联模型,获取广告位信息,具体代码如下:

  public function position()
    {
        return $this->belongsTo('App\Adv', 'advid', 'id');
    }

(8)在Adv控制器中引入Advcontent的命名空间,具体代码如下:

use App\Content;

(9)通过浏览器访问,可以对广告内容进行显示、编辑、删除的操作。

七、 总结

1、学习laravel的难点

MVC 模式:Laravel 是一个基于 MVC 模式的 Web 框架,它将应用程序分为三部分:模型(Model)、视图(View)和控制器(Controller)。掌握 MVC 模式并理解如何在 Laravel 中使用它需要比较长时间的学习和实践。

命名空间和自动加载:Laravel 使用 Composer 的自动加载机制来加载所有类和文件。这意味着你需要理解 Laravel 应用程序的命名空间和 Composer 自动加载器的工作原理。

Eloquent ORM:Laravel 的 Eloquent ORM 是一个功能强大的 ORM 工具,用于在应用程序和数据库之间进行交互。你需要熟悉 Eloquent ORM 的API和查询语法才能有效地使用它。

Blade 模板引擎:Laravel 使用 Blade 模板引擎来生成 HTML 响应。你需要理解 Blade 的基本语法、模板继承和控制指令。

artisan 命令行工具:Laravel 的 artisan 命令行工具提供了许多便捷的命令,如数据库迁移、生成模型、生成控制器等。你需要了解如何使用和扩展这些命令。

2、学习laravel收获到了什么

熟练掌握流行的PHP框架。Laravel是一个流行的PHP框架,熟练掌握它可以让你成为一名优秀的PHP开发人员,并拥有更好的职业前景。

更高效的开发。Laravel提供了许多有用的工具和插件,可以帮助开发人员更快地开发Web应用程序和API,并提高开发效率。

构建高质量的Web应用程序和API。Laravel提供了许多有用的功能,例如身份验证、授权、缓存、队列处理和命令行工具等,可以帮助开发人员构建高质量的Web应用程序和API。

学习面向对象编程。Laravel采用了面向对象编程的方法,让开发人员更好地理解OO编程的概念和原则,并增强了代码的可重用性和可维护性。

参与到开源社区中。Laravel是一个开源框架,并拥有庞大的社区。学习Laravel可以帮助你更好地参与到开源社区中,并与其他开发人员合作学习和交流。

 3、内容管理系统项目心得总结

       内容管理系统项目的学习,让我掌握了内容管理系统中常见的功能的开发,理解框架在开发中的作用,体会项目开发的完整流程 ,能够根据实际需要对项目中的功能进行修改和扩展,为以后开发更加复杂的项目打下基础。

        通过laravel框架实现内容管理系统项目,我深刻认识到了Laravel框架的优秀特性。它不仅提供了丰富的功能集,同时也能够大大提高开发效率和代码可读性,并且在安全方面也考虑得非常周到。

        总之,使用 Laravel 框架实现内容管理系统可以带来很多便利和灵活性,同时也需要注意安全性和性能优化等问题。Laravel 框架提供了丰富的组件和工具,使得内容管理系统的开发变得更加简单和高效。以上就是我对laravel框架学习的心得体会