laravel框架后台内容管理系统项目搭建心得分享
laravel框架后台内容管理系统项目搭建心得分享
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 | 包含了数据迁移及填充文件 |
| Public | Public |
| Resources | resources目录包含了视图文件及原生资源文件 |
| 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框架学习的心得体会