Laravel搭建迷你博客

部署

项目是直接部署在WampServer环境 版本:3.0.6 (PHP7.0+)

安装框架

使用composer包管理器安装Laravel框架,使用的是Laravel5.4版本

1
composer create-project laravel/laravel blog --prefer-dist

配置Apache

1
2
3
4
5
6
7
8
9
<VirtualHost *:80>
ServerName miniblog.com
DocumentRoot G:/wamp64/www/blog/public/
<Directory "G:/wamp64/www/blog/public/">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
</VirtualHost>

添加Hosts

127.0.0.1 miniblog.com

数据库配置

创建数据库

CREATE DATABASE blog /!40100 COLLATE ‘utf8mb4_general_ci’ /;

修改.env文件

1
2
3
4
5
6
7
APP_NAME=迷你博客
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=

开始制作

创建控制器

1
php artisan make:controller ArticlesController

创建路由

打开routes文件夹中web.php加入以下代码:

1
Route::resource('articles','ArticlesController');

只需要上面这样一行代码,就相当于创建了如下7条路由,且都是命名路由,我们可以使用类似route('articles.show') 这样的用法。

1
2
3
4
5
6
7
Route::get('/articles', 'ArticlesController@index')->name('articles.index');
Route::get('/articles/{id}', 'ArticlesController@show')->name('articles.show');
Route::get('/articles/create', 'ArticlesController@create')->name('articles.create');
Route::post('/articles', 'ArticlesController@store')->name('articles.store');
Route::get('/articles/{id}/edit', 'ArticlesController@edit')->name('articles.edit');
Route::patch('/articles/{id}', 'ArticlesController@update')->name('articles.update');
Route::delete('/articles/{id}', 'ArticlesController@destroy')->name('articles.destroy');

如果你使用的PHPStrom的自带终端或者其他终端软件,在项目文件夹下输入

1
php artisan route:list

可以查看到路由表所有信息。

创建注册登录

这里还是使用Laravel自带的注册登录组件,在项目下的终端输入

1
php artisan make:auth

验证码扩展包

Composer验证码包简介:https://packagist.org/packages/mews/captcha

也用中文验证码包:https://packagist.org/packages/kangkang66/captcha

安装

1
composer require mews/captcha

配置

使用Captcha服务提供者之前还需要在config/app.php中注册服务提供者:

1
2
3
4
'providers' => [
// ...
Mews\Captcha\CaptchaServiceProvider::class,
]

同时注册下相应门面:

1
2
3
4
'aliases' => [
// ...
'Captcha' => Mews\Captcha\Facades\Captcha::class,
]

如果要使用自定义的配置,还可以发布配置文件到config目录:

1
php artisan vendor:publish

编辑新生成的Captcha.php

重写默认登录注册验证方法

找到:app\Http\Controllers\Auth\LoginController.php
进入use AuthenticatesUsers类找到validateLogin方法,修改验证方法代码如下:

1
2
3
4
5
6
7
8
9
10
11
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string',
'captcha' =>'required|captcha|max:5|string'
],[
'captcha.captcha'=>trans('验证码错误!'),
'captcha.required'=>trans('验证码为必须!'),
]);
}

同理,也可以在注册也添加上验证码:
找到app\Http\Controllers\Auth\RegisterController.php
修改验证:

1
2
3
4
5
6
7
8
9
10
11
12
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'captcha'=>'required|max:5|captcha|string'
],[
'captcha.captcha'=>trans('验证码错误!'),
'captcha.required'=>trans('验证码为空!')
]);
}

对视图文件的添加

添加验证码图片+验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="form-group{{ $errors->has('captcha') ? ' has-error' : '' }}">
<label for="text" class="col-md-4 control-label">验证码</label>

<div class="col-md-6">
<input id="text" type="captcha" class="form-control" name="captcha" required>
<br/>
<span class="input-group-btn">
<img style="" src="{{captcha_src()}}"
onclick="this.src='{{captcha_src()}}' + Math.random()">
</span>
@if ($errors->has('captcha'))
<span class="help-block">
<strong>{{ $errors->first('captcha') }}</strong>
</span>
@endif
</div>
</div>

创建数据表

利用 artisan 命令生成迁移:

1
php artisan make:migration create_articles_talbe

然后打开迁移文件:

database/migrations/XXXX_create_articles_table.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('articles',function (Blueprint $table){
$table->increments('id');
$table->string('title');
$table->longText('content')->nullable();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('articles');
}
}

在Laravel5.4中要修改默认字符串长度,app/Providers/AppServiceProvider.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

namespace App\Providers;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}

/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}

生成数据表

在终端里输入

1
php artisan migrate

如果有错误或者需要修改,可以使用下面命令

1
php artisan migrate:rollback

创建模型

利用 artisan 命令创建模型:

1
php artisan make:model Article

打开模型文件,输入以下代码:

app/Article.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
protected $table = 'articles';

protected $fillable = [
'title',
'content',
];
}

这样就可以指定某个表的可写字段。

1
php artisan route:list

可以查看到每个路由的控制器的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
+--------+-----------+-------------------------+------------------+------------------------------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/user | | Closure | api,auth:api |
| | GET|HEAD | articles | articles.index | App\Http\Controllers\ArticlesController@index | web |
| | POST | articles | articles.store | App\Http\Controllers\ArticlesController@store | web |
| | GET|HEAD | articles/create | articles.create | App\Http\Controllers\ArticlesController@create | web |
| | GET|HEAD | articles/{article} | articles.show | App\Http\Controllers\ArticlesController@show | web |
| | PUT|PATCH | articles/{article} | articles.update | App\Http\Controllers\ArticlesController@update | web |
| | DELETE | articles/{article} | articles.destroy | App\Http\Controllers\ArticlesController@destroy | web |
| | GET|HEAD | articles/{article}/edit | articles.edit | App\Http\Controllers\ArticlesController@edit | web |
| | GET|HEAD | home | home | App\Http\Controllers\HomeController@index | web,auth |
| | GET|HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest |
| | POST | login | | App\Http\Controllers\Auth\LoginController@login | web,guest |
| | POST | logout | logout | App\Http\Controllers\Auth\LoginController@logout | web |
| | POST | password/email | password.email | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail | web,guest |
| | GET|HEAD | password/reset | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest |
| | POST | password/reset | | App\Http\Controllers\Auth\ResetPasswordController@reset | web,guest |
| | GET|HEAD | password/reset/{token} | password.reset | App\Http\Controllers\Auth\ResetPasswordController@showResetForm | web,guest |
| | GET|HEAD | register | register | App\Http\Controllers\Auth\RegisterController@showRegistrationForm | web,guest |
| | POST | register | | App\Http\Controllers\Auth\RegisterController@register | web,guest |
+--------+-----------+-------------------------+------------------+------------------------------------------------------------------------+--------------+

创建、修改视图

然后在 resources/views 目录下新建一个文件夹 articles ,然后在 resources/views/articles 目录下新建文件 edit.blade.phpcreate.blade.phpindex.blade.php

修改create.blade.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<form action="{{route('articles.store')}}" method="post" role="form">
<div class="form-group">
{{ csrf_field() }}
<label for="title">标题</label>
<input class="form-control" type="text" name="title" value="{{old('title')}}">
<label for="name">文本框</label>
<textarea class="form-control" name="articleContent" rows="3"></textarea>
<button class="btn btn-primary" style="margin-top:8px; float: right" type="submit">提交</button>
</div>
</form>
</div>
</div>
</div>
@endsection

创建文章

然后在ArticlesController.php创建create()的方法

1
2
3
public function create(){
return view('articles.create');
}

现在就可以访问http://xxxxx/articles/create,显示创建文章视图,From访问的是储存文章的路由。现在可以写储存文章的方法了。

储存文章

打开 ArticlesController.php 控制器,创建store() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace App\Http\Controllers;

use App\Article;//因为这段代码中用到了Eloquent 模型的构造器用法,所以需要引入我们之前创建的模型。
use Illuminate\Http\Request;

class ArticlesController extends Controller
{
public function store(Request $request){
$this->validate($request,[
'title'=>'required|max:50',//在收到表单传过来的数据时,可以先对表单数据进行验证
]);

$article = Article::create([
'title' => $request->title,
'content' => $request->articleContent,
]);
return redirect()->route('article.index');//最后完成文章的创建,然后重定向到文章列表页
}
}

文章首页

创建index()方法

1
2
3
4
public function index(){
$articles = Article::orderBy('created_at','desc')->get();
return view('articles.index',compact('articles'));
}

修改articles.index的视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@extends('layouts.app')
@section('content')

<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<a class="btn btn-primary" href="{{route('articles.create')}}" style="margin-bottom: 8px;">创建文章</a>


@foreach($articles as $article)


<a href="{{route('articles.edit',$article->id)}}" style="display: block;text-decoration: none;">
<div class="panel panel-default">
<div class="panel-heading">{{$article->title}}</div>

<div class="panel-body">
{{$article->content}}
</div>
<div class="panel-footer">
<form action="{{route('articles.destroy',$article->id)}}" method="post" style="display: block;">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="submit" class="btn btn-default">删除</button>
</form>


</div>
</div>
</a>
@endforeach
</div>
</div>
</div>
@endsection

好了,现在创建文章和显示文章列表都有了,现在我们做修改文章和删除文章

修改文章

创建edit()方法

1
2
3
4
public function edit($id){
$article = Article::findOrFail($id);
return view('articles.edit',compact('article'));
}

更新文章

创建update()方法

1
2
3
4
5
6
7
8
9
10
11
public function update(Request $request,$id){
$this->validate($request,[
'title'=>'required|max:50'
]);
$article=Article::findOrFail($id);
$article->update([
'title'=>$request->title,
'content'=>$request->articleContent,
]);
return redirect()->route('articles.index');
}

修改articles.edit视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 @extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<form action="{{route('articles.update',$article->id)}}" method="post" role="form">
<div class="form-group">
{{ csrf_field() }}
{{ method_field('PATCH') }}
<label for="title">标题</label>
<input class="form-control" type="text" name="title" value="{{$article->title}}">
<label for="name">文本框</label>
<textarea class="form-control" name="articleContent" rows="3">{{$article->content}}</textarea>
<button class="btn btn-primary" style="margin-top:8px; float: right" type="submit">提交</button>
</div>
</form>
</div>
</div>
</div>
@endsection

删除文章

现在满足了修改更新,下面我们来写删除。修改destroy()

1
2
3
4
5
public function destroy($id){
$article=Article::findOrfail($id);
$article->delete();
return back();
}

现在我们已经满足了,博客的基本的增、删、改、查、的功能,现在我们添加中间件,只有登录后才能使用博客。

添加登录中间件

打开 ArticlesController.php 控制器,创建__construct() 方法。

1
2
3
4
public function __construct()
{
$this->middleware('auth');
}

打开app/Http/Middleware/RedirectIfAuthenticated.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/articles');//修改重定向到文章列表页
}

return $next($request);
}
}

打开app/Http/Controllers/Auth/LoginController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/

use AuthenticatesUsers;

/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/articles';//修改重定向到文章页

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}

修改welcome.blade.php视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<!doctype html>
<html lang="{{ config('app.locale') }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Laravel</title>

<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">

<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Raleway', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}

.full-height {
height: 100vh;
}

.flex-center {
align-items: center;
display: flex;
justify-content: center;
}

.position-ref {
position: relative;
}

.top-right {
position: absolute;
right: 10px;
top: 18px;
}

.content {
text-align: center;
}

.title {
font-size: 84px;
}

.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 12px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}

.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@if (Auth::check())
<a href="{{ route('articles.index') }}">博客</a>
@else
<a href="{{ url('/login') }}">登录</a>
<a href="{{ url('/register') }}">注册</a>
@endif
</div>
@endif

<div class="content">
<div class="title m-b-md">
迷你博客 <a href="{{route('articles.index')}}">点我进入</a>
</div>

<div class="links">
<a href="https://laravel.com/docs">Documentation</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
</div>
</body>
</html>

文章控制器完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php

namespace App\Http\Controllers;

use App\Article;//因为这段代码中用到了Eloquent 模型的构造器用法,所以需要引入我们之前创建的模型。
use Illuminate\Http\Request;

class ArticlesController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function create(){
return view('articles.create');
}
public function edit($id){
$article = Article::findOrFail($id);
return view('articles.edit',compact('article'));
}
public function index(){
$articles = Article::orderBy('created_at','desc')->get();
return view('articles.index',compact('articles'));
}
public function store(Request $request){
$this->validate($request,[
'title'=>'required|max:50',//在收到表单传过来的数据时,可以先对表单数据进行验证
]);

$article = Article::create([
'title' => $request->title,
'content' => $request->articleContent,
]);
return redirect()->route('articles.index');//最后完成文章的创建,然后重定向到文章列表页
}
public function update(Request $request,$id){
$this->validate($request,[
'title'=>'required|max:50'
]);
$article=Article::findOrFail($id);
$article->update([
'title'=>$request->title,
'content'=>$request->articleContent,
]);
return redirect()->route('articles.index');
}
public function destroy($id){
$article=Article::findOrfail($id);
$article->delete();
return back();
}
}

DEMO项目地址

https://coding.net/u/Colorful_Ghost/p/Laravel-Miniblog/git