第一个应用 #

一、项目概述 #

1.1 目标 #

创建一个简单的博客系统,包含以下功能:

功能 说明
文章列表 显示所有文章
创建文章 添加新文章
查看文章 查看文章详情
编辑文章 修改文章内容
删除文章 删除文章

1.2 涉及知识点 #

text
学习内容
├── 路由定义
├── 控制器创建
├── 视图渲染
├── 数据库迁移
├── Eloquent模型
├── 表单处理
└── 数据验证

二、创建项目 #

2.1 新建项目 #

bash
# 创建新项目
composer create-project laravel/laravel blog

# 进入项目目录
cd blog

# 启动开发服务器
php artisan serve

2.2 配置数据库 #

修改 .env 文件:

env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=your_password

2.3 生成应用密钥 #

bash
php artisan key:generate

三、创建数据库迁移 #

3.1 创建文章表迁移 #

bash
php artisan make:migration create_posts_table

3.2 编辑迁移文件 #

php
// database/migrations/xxxx_xx_xx_xxxxxx_create_posts_table.php

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

return new class extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
};

3.3 执行迁移 #

bash
php artisan migrate

四、创建模型 #

4.1 创建Post模型 #

bash
php artisan make:model Post

4.2 编辑模型 #

php
// app/Models/Post.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = [
        'title',
        'content',
    ];
}

五、创建控制器 #

5.1 创建资源控制器 #

bash
php artisan make:controller PostController --resource

5.2 实现控制器方法 #

php
// app/Http/Controllers/PostController.php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::latest()->paginate(10);
        return view('posts.index', compact('posts'));
    }

    public function create()
    {
        return view('posts.create');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
        ]);

        Post::create($validated);

        return redirect()->route('posts.index')
            ->with('success', '文章创建成功!');
    }

    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }

    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    public function update(Request $request, Post $post)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
        ]);

        $post->update($validated);

        return redirect()->route('posts.index')
            ->with('success', '文章更新成功!');
    }

    public function destroy(Post $post)
    {
        $post->delete();

        return redirect()->route('posts.index')
            ->with('success', '文章删除成功!');
    }
}

六、定义路由 #

6.1 添加资源路由 #

php
// routes/web.php

use App\Http\Controllers\PostController;

Route::resource('posts', PostController::class);

6.2 查看路由列表 #

bash
php artisan route:list

输出结果:

text
+--------+-----------+------------------+---------------+
| Method | URI       | Name             | Action        |
+--------+-----------+------------------+---------------+
| GET    | posts     | posts.index      | PostController@index   |
| GET    | posts/create | posts.create  | PostController@create  |
| POST   | posts     | posts.store      | PostController@store   |
| GET    | posts/{post} | posts.show    | PostController@show    |
| GET    | posts/{post}/edit | posts.edit | PostController@edit  |
| PUT    | posts/{post} | posts.update  | PostController@update  |
| DELETE | posts/{post} | posts.destroy | PostController@destroy |
+--------+-----------+------------------+---------------+

七、创建视图 #

7.1 创建布局文件 #

blade
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', '我的博客')</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="{{ route('posts.index') }}">我的博客</a>
        </div>
    </nav>

    <main class="container py-4">
        @if(session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        @yield('content')
    </main>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

7.2 文章列表视图 #

blade
<!-- resources/views/posts/index.blade.php -->
@extends('layouts.app')

@section('title', '文章列表')

@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
    <h1>文章列表</h1>
    <a href="{{ route('posts.create') }}" class="btn btn-primary">新建文章</a>
</div>

<table class="table table-striped">
    <thead>
        <tr>
            <th>ID</th>
            <th>标题</th>
            <th>创建时间</th>
            <th>操作</th>
        </tr>
    </thead>
    <tbody>
        @foreach($posts as $post)
        <tr>
            <td>{{ $post->id }}</td>
            <td>{{ $post->title }}</td>
            <td>{{ $post->created_at->format('Y-m-d H:i') }}</td>
            <td>
                <a href="{{ route('posts.show', $post) }}" class="btn btn-sm btn-info">查看</a>
                <a href="{{ route('posts.edit', $post) }}" class="btn btn-sm btn-warning">编辑</a>
                <form action="{{ route('posts.destroy', $post) }}" method="POST" style="display:inline">
                    @csrf
                    @method('DELETE')
                    <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('确定删除?')">删除</button>
                </form>
            </td>
        </tr>
        @endforeach
    </tbody>
</table>

{{ $posts->links() }}
@endsection

7.3 创建文章视图 #

blade
<!-- resources/views/posts/create.blade.php -->
@extends('layouts.app')

@section('title', '创建文章')

@section('content')
<h1 class="mb-4">创建文章</h1>

<form action="{{ route('posts.store') }}" method="POST">
    @csrf

    <div class="mb-3">
        <label for="title" class="form-label">标题</label>
        <input type="text" class="form-control @error('title') is-invalid @enderror" 
               id="title" name="title" value="{{ old('title') }}">
        @error('title')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <div class="mb-3">
        <label for="content" class="form-label">内容</label>
        <textarea class="form-control @error('content') is-invalid @enderror" 
                  id="content" name="content" rows="10">{{ old('content') }}</textarea>
        @error('content')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <button type="submit" class="btn btn-primary">提交</button>
    <a href="{{ route('posts.index') }}" class="btn btn-secondary">取消</a>
</form>
@endsection

7.4 文章详情视图 #

blade
<!-- resources/views/posts/show.blade.php -->
@extends('layouts.app')

@section('title', $post->title)

@section('content')
<div class="mb-4">
    <a href="{{ route('posts.index') }}" class="btn btn-secondary">返回列表</a>
    <a href="{{ route('posts.edit', $post) }}" class="btn btn-warning">编辑</a>
</div>

<h1>{{ $post->title }}</h1>
<p class="text-muted">创建于 {{ $post->created_at->format('Y-m-d H:i') }}</p>

<hr>

<div class="content">
    {{ $post->content }}
</div>
@endsection

7.5 编辑文章视图 #

blade
<!-- resources/views/posts/edit.blade.php -->
@extends('layouts.app')

@section('title', '编辑文章')

@section('content')
<h1 class="mb-4">编辑文章</h1>

<form action="{{ route('posts.update', $post) }}" method="POST">
    @csrf
    @method('PUT')

    <div class="mb-3">
        <label for="title" class="form-label">标题</label>
        <input type="text" class="form-control @error('title') is-invalid @enderror" 
               id="title" name="title" value="{{ old('title', $post->title) }}">
        @error('title')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <div class="mb-3">
        <label for="content" class="form-label">内容</label>
        <textarea class="form-control @error('content') is-invalid @enderror" 
                  id="content" name="content" rows="10">{{ old('content', $post->content) }}</textarea>
        @error('content')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <button type="submit" class="btn btn-primary">更新</button>
    <a href="{{ route('posts.index') }}" class="btn btn-secondary">取消</a>
</form>
@endsection

八、添加首页路由 #

8.1 修改欢迎页面 #

php
// routes/web.php

use App\Http\Controllers\PostController;

Route::get('/', function () {
    return redirect()->route('posts.index');
});

Route::resource('posts', PostController::class);

九、数据填充 #

9.1 创建Seeder #

bash
php artisan make:seeder PostSeeder

9.2 编辑Seeder #

php
// database/seeders/PostSeeder.php

namespace Database\Seeders;

use App\Models\Post;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    public function run()
    {
        $posts = [
            [
                'title' => 'Laravel入门教程',
                'content' => '这是一篇关于Laravel入门的教程文章...',
            ],
            [
                'title' => 'Eloquent ORM详解',
                'content' => 'Eloquent是Laravel的ORM实现...',
            ],
            [
                'title' => 'Blade模板引擎',
                'content' => 'Blade是Laravel强大的模板引擎...',
            ],
        ];

        foreach ($posts as $post) {
            Post::create($post);
        }
    }
}

9.3 运行Seeder #

bash
php artisan db:seed --class=PostSeeder

十、测试应用 #

10.1 启动服务器 #

bash
php artisan serve

10.2 访问应用 #

text
打开浏览器访问: http://localhost:8000

10.3 功能测试清单 #

功能 测试项
列表 访问 /posts 查看文章列表
创建 点击"新建文章",填写表单提交
查看 点击"查看"按钮查看文章详情
编辑 点击"编辑"按钮修改文章
删除 点击"删除"按钮删除文章

十一、项目总结 #

11.1 文件清单 #

text
创建的文件
├── database/migrations/
│   └── xxxx_create_posts_table.php
├── app/Models/
│   └── Post.php
├── app/Http/Controllers/
│   └── PostController.php
├── resources/views/
│   ├── layouts/
│   │   └── app.blade.php
│   └── posts/
│       ├── index.blade.php
│       ├── create.blade.php
│       ├── show.blade.php
│       └── edit.blade.php
└── database/seeders/
    └── PostSeeder.php

11.2 学到的知识点 #

知识点 说明
迁移 数据库表结构定义
模型 Eloquent ORM使用
控制器 请求处理和响应
路由 资源路由定义
视图 Blade模板渲染
验证 表单数据验证
表单 CSRF保护和表单构建

11.3 下一步 #

恭喜你完成了第一个Laravel应用!接下来让我们深入学习 路由基础,掌握Laravel路由系统!

最后更新:2026-03-28