Laravel写博客系统练习 CRUD 操作

2023-06-1307:02:20后端程序开发Comments1,002 views字数 10117阅读模式

写一个很简单的博客系统,它只有文章,每篇文章都有一个标题和内容。将通过这个示例来演示如何从数据库中查询数据、如何创建/更新数据、如何将它们保存在数据库中,以及如何删除它们。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

1. 数据库结构设计

首先,我们先生成数据库。我们将为 post 表创建一个迁移文件。该表包含标题和内容。使用以下命令生成迁移文件:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

php artisan make:migration create_posts_table
<?php

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

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

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

在这个例子当中,我们在 post 表中创建了五列:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

  • id:主键
  • timestamps():创建两个字段 created_atupdated_at 。这两个字段会在创建和更新数据时自动更新。
  • string('title'):创建 title 字段,类型为 VARCHAR,默认长度为 255 字节
  • string('content'):创建 content 字段

这样,在数据库当中就会生成一张 posts文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

Laravel写博客系统练习 CRUD 操作文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

现在,我们可以为这张表创建相应的模型。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

php artisan make:model Post

app/Models/Post.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
}

并生成对应的资源控制器:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

php artisan make:controller PostController --resource

最后,在路由器中注册这个控制器:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

use App\Http\Controllers\PostController;

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

还可以通过运行以下命令来检查注册了哪些路由:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

php artisan route:list
GET|HEAD        posts ................................................................. posts.index › PostController@index
POST            posts ................................................................. posts.store › PostController@store
GET|HEAD        posts/create ........................................................ posts.create › PostController@create
GET|HEAD        posts/{post} ............................................................ posts.show › PostController@show
PUT|PATCH       posts/{post} ........................................................ posts.update › PostController@update
DELETE          posts/{post} ...................................................... posts.destroy › PostController@destroy
GET|HEAD        posts/{post}/edit ....................................................... posts.edit › PostController@edit

可以看到,这些信息包含请求方法、控制器方法以及路由名称等信息。这些信息非常重要,我们将在本文后面用到它们。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

2. CURD 操作

一般来说,用户应该能够对每个资源执行四个操作,在我们的例子中,就是:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

  • 创建:用户应该能够创建新资源并将它们保存在数据库中。
  • 读取:用户应该能够读取资源,既可以检索资源列表,也可以检查特定资源的详细信息。
  • 更新:用户应该能够更新现有的资源,并更新相应的数据库记录。
  • 删除:用户应该能够从数据库中删除资源。

它们一起被称为 CRUD 操作。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

2.1 创建

现在,我们的数据库仍然是空的,因此用户可能想要创建新帖子。因此,让我们从创建 (C) 操作开始。要完成此创建操作,需要做两件事:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

  • 一个 create() 控制器方法,它显示一个表单,允许用户填写标题和内容。
  • 一个 store() 控制器方法,它将新创建的帖子保存到数据库,并将用户重定向到列表页面。

方法 create() 匹配URL模式 /posts/createGETmethod),store()方法匹配URL /postPOSTmethod)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

简要回顾一下 HTTP 方法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

  • GET方法是最常用的 HTTP 请求方法。它用于向服务器请求数据和资源。
  • POST方法用于向服务器发送数据,用于创建/更新资源。
  • HEAD方法就像GET方法一样工作。除了 HTTP 响应将只包含头部而不包含主体。此方法通常由开发人员用于调试目的。
  • PUT 方法类似于POST,只有一点点不同。当您的POST资源已存在于服务器上时,此操作不会造成任何差异。但是,该PUT方法会在您每次发出请求时复制该资源。
  • DELETE 方法从服务器中删除资源。

让我们从create()方法开始:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

app/Http/Controllers/PostController.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Contracts\View\View;
. . .

class PostController extends Controller
{
    . . .

    /**
     * Show the form for creating a new resource.
     */
    public function create(): View
    {
        return view('posts.create');
    }

    . . .
}

当您发送 GET 请求时将执行 /posts/create 方法,并且它指向视图 views/posts/create.blade.php。请注意第 16 行,Response 已更改为 View,因为此方法需要返回一个视图。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

接下来,我们应该创建相应的视图。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

views/layout.blade.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.tailwindcss.com"></script>
    @yield('title')
</head>

<body class="container mx-auto font-serif">
    <div class="bg-white text-black font-serif">
        <div id="nav">
            <nav class="flex flex-row justify-between h-16 items-center shadow-md">
                <div class="px-5 text-2xl">
                    <a href="{{ route('posts.index') }}">
                        My Blog
                    </a>
                </div>
                <div class="hidden lg:flex content-between space-x-10 px-10 text-lg">
                    <a href="{{ route('posts.create') }}" class="hover:underline hover:underline-offset-1">New Post</a>
                    <a href="https://github.com/ericnanhu" class="hover:underline hover:underline-offset-1">GitHub</a>
                </div>
            </nav>
        </div>

        @yield('content')

        <footer class="bg-gray-700 text-white">
            <div
                class="flex justify-center items-center sm:justify-between flex-wrap lg:max-w-screen-2xl mx-auto px-4 sm:px-8 py-10">
                <p class="font-serif text-center mb-3 sm:mb-0">Copyright © <a href="https://www.ericsdevblog.com/"
                        class="hover:underline">Eric Hu</a></p>

                <div class="flex justify-center space-x-4">
                    . . .
                </div>
            </div>
        </footer>
    </div>
</body>

</html>

第 17 和 22 行,双花括号 ( {{ }}) 允许我们在模板内部执行 PHP 代码,在这种情况下,该route('posts.index')方法将返回名称为 posts.index 的路由。你可以参考php artisan route:list命令的输出结果来查看路由名称。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

由于此 create视图用于发布相关操作,因此我创建了一个post 目录来保存此视图。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

views/posts/create.blade.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

@extends('layout')

@section('title')
<title>Create</title>
@endsection

@section('content')
<div class="w-96 mx-auto my-8">
    <h2 class="text-2xl font-semibold underline mb-4">Create new post</h2>
    <form action="{{ route('posts.store') }}" method="POST">
        {{ csrf_field() }}
        <label for="title">Title:</label><br>
        <input type="text" id="title" name="title"
            class="p-2 w-full bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300"><br>
        <br>
        <label for="content">Content:</label><br>
        <textarea type="text" id="content" name="content" rows="15"
            class="p-2 w-full bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300"></textarea><br>
        <br>
        <button type="submit"
            class="font-sans text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-md text-sm w-full px-5 py-2.5 text-center">Submit</button>
    </form>
</div>
@endsection

在使用表单传输数据时,我们需要注意一些事项。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

第 10 行的posts.store,action 属性定义了提交此表单时请求的地址。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

第 11 行,{{ csrf_field() }}。CSRF 是一种针对Web 应用程序的恶意攻击,此csrf_field()功能可针对此类攻击提供保护。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

第13、17行,注意属性name。提交表单时,用户输入信息将绑定到一个变量,该变量的名称由属性name指定。例如,当 时name="title",用户输入将绑定到变量title,我们可以使用 $request->input('title') 获取它的值。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

第 20 行,type必须将属性设置submit为 才能使此表单工作。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

现在启动开发服务器并转到http://127.0.0.1:8000/posts/create文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

Laravel写博客系统练习 CRUD 操作文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

单击提交按钮时,浏览器将向服务器发送 POST 请求,此时将执行 store() 方法。此POST请求将包含用户输入,并且可以像这样访问它们:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

PostController.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<?php

namespace App\Http\Controllers;

. . .

class PostController extends Controller
{
    . . .

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): RedirectResponse
    {
        // Get the data from the request
        $title = $request->input('title');
        $content = $request->input('content');

        // Create a new Post instance and put the requested data to the corresponding column
        $post = new Post;
        $post->title = $title;
        $post->content = $content;

        // Save the data
        $post->save();

        return redirect()->route('posts.index');
    }

    . . .
}

保存数据后,将被重定向到 posts.index 路由。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

返回浏览器并输入新的标题和内容,然后单击提交按钮。视图index尚未创建,因此将返回一条错误消息。但是,如果查看数据库,应该可以看到新添加的一条记录。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

2.2 列表

PostController.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(): View
    {
        $posts = Post::all();

        return view('posts.index', [
            'posts' => $posts,
        ]);
    }

    . . .
}

相应的 index 视图:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

views/post/index.blade.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

@extends('layout')

@section('title')
<title>Page Title</title>
@endsection

@section('content')
<div class="max-w-screen-lg mx-auto my-8">
    @foreach($posts as $post)
    <h2 class="text-2xl font-semibold underline mb-2"><a href="{{ route('posts.show', ['post' => $post->id]) }}">{{ $post->title }}</a></h2>
    <p class="mb-4">{{ Illuminate\Support\Str::words($post->content, 100) }}</p>
    @endforeach
</div>
@endsection

第 9 行,foreach遍历 $posts 变量,并将每个值赋给变量 $post文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

第 10 行,注意帖子id 是如何传递给 posts.show 路由的。然后路由会将此变量传递给show()控制器方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

第 11 行,该 Str::words() 方法是一个 PHP 帮助方法,它只会取 content的前 100 个单词。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

2.3 更新

接下来,对于更新操作,我们有edit()显示 HTML 表单的方法,以及update()对数据库进行更改的方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

PostController.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class PostController extends Controller
{
    . . .

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id): View
    {
        $post = Post::all()->find($id);

        return view('posts.edit', [
            'post' => $post,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id): RedirectResponse
    {
        // Get the data from the request
        $title = $request->input('title');
        $content = $request->input('content');

        // Find the requested post and put the requested data to the corresponding column
        $post = Post::all()->find($id);
        $post->title = $title;
        $post->content = $content;

        // Save the data
        $post->save();

        return redirect()->route('posts.show', ['post' => $id]);
    }

    . . .
}

views/post/edit.blade.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

@extends('layout')

@section('title')
<title>Edit</title>
@endsection

@section('content')
<div class="w-96 mx-auto my-8">
    <h2 class="text-2xl font-semibold underline mb-4">Edit post</h2>
    <form action="{{ route('posts.update', ['post' => $post->id]) }}" method="POST">
        {{ csrf_field() }}
        {{ method_field('PUT') }}
        <label for="title">Title:</label><br>
        <input type="text" id="title" name="title" value="{{ $post->title }}"
            class="p-2 w-full bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300"><br>
        <br>
        <label for="content">Content:</label><br>
        <textarea type="text" id="content" name="content" rows="15"
            class="p-2 w-full bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300">{{ $post->content }}</textarea><br>
        <br>
        <button type="submit"
                class="font-sans text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-md text-sm w-full px-5 py-2.5 text-center">Submit</button>
    </form>
</div>
@endsection

2.4 删除

最后,destroy()方法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

PostController.php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class PostController extends Controller
{
    . . .

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id): RedirectResponse
    {
        $post = Post::all()->find($id);

        $post->delete();

        return redirect()->route('posts.index');
    }
}

此操作不需要视图,它只是在操作完成后将页面重定向到posts.index文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html

作者:金刀大菜牙
来源:稀土掘金
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/46866.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/46866.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定