Laravel 11 书评网2--书籍模块

116 阅读3分钟

创建书籍迁移文件

php artisan make:migration create_books_table

2024_11_11_122247_create_books_table.php

public function up(): void
{
    Schema::create('books', function (Blueprint $table) {
        $table->id();
        $table->string('titel');
        $table->string('author');
        $table->text('description')->nullable();
        $table->string('image')->nullable();
        $table->integer('status')->default(1);
        $table->timestamps();
    });
}

执行迁移

php artisan migrate

路由

Route::group(['middleware' => 'auth'], function () {
   

    // 书籍页
    Route::get('books', [\App\Http\Controllers\BookController::class, 'index'])
        ->name('books.index');
    // 书籍新增
    Route::get('books/create', [\App\Http\Controllers\BookController::class, 'create'])
        ->name('books.create');
    // 执行书籍新增
    Route::post('books', [\App\Http\Controllers\BookController::class, 'store'])
        ->name('books.store');
    // 书籍编辑页面
    Route::get('books/edit/{id}', [\App\Http\Controllers\BookController::class, 'edit'])
        ->name('books.edit');
    // 执行书籍编辑
    Route::post('books/edit/{id}', [\App\Http\Controllers\BookController::class, 'update'])
        ->name('books.update');
    // 删除书籍
    Route::delete('books', [\App\Http\Controllers\BookController::class, 'destroy'])
        ->name('books.destroy');
});

控制器

php artisan make:controller BookController

app/http/ControllersBookController.php

<?php

namespace App\Http\Controllers;

use App\Models\Book;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Validator;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\ImageManager;

class BookController extends Controller
{
    // 书籍首页
    public function index(Request $request)
    {
        $books = Book::orderBy('created_at', 'DESC');

        // 搜索标题
        if (!empty($request->keyword)) {
            $books->where('title', 'like', '%' . $request->keyword . '%');
        };

        $books = $books->paginate(3);

        return view('books.list', compact('books'));
    }

    // 显示创建图书页
    public function create()
    {
        return view('books.create');
    }

    // 执行图书创建
    public function store(Request $request)
    {
        $rules = [
            'title' => 'required|min:2',
            'author' => 'required|min:3',
            'status' => 'required'
        ];

        if (!empty($request->image)) {
            $rules['image'] = 'required|image|mimes:jpeg,png,jpg|max:2048';
        }

        // 验证
        $validator = Validator::make($request->all(), $rules);

        // 如果验证失败,我们将返回错误
        if ($validator->fails()) {
            return redirect()->route('books.create')->withErrors($validator)->withInput();
        }

        // 执行书籍新增
        $book = new Book();
        $book->title = $request->title;
        $book->author = $request->author;
        $book->description = $request->description;
        $book->status = $request->status;
        $book->save();

        // 这里上传图片
        if (!empty($request->image)) {

            $image = $request->image;
            $ext = $image->getClientOriginalExtension(); // 获取原图片名称
            $image_name = time() . '.' . $ext; // 生成时间戳唯一名称
            $image->move(public_path('uploads/books'), $image_name);

            $book->image = $image_name;
            $book->save();

            // 创建缩略图
            $manager = new ImageManager(Driver::class);
            $img = $manager->read(public_path('uploads/books/' . $image_name));

            $img->resize(990); // 调整图片大小
            $img->save(public_path('uploads/books/thumb/' . $image_name)); // 存放在uploads/books/thumb
        }

        return redirect()->route('books.index')->with('sucsess', '新增书籍成功~~');

    }

    // 书籍编辑页
    public function edit($id)
    {
        $book = Book::findOrFail($id);
        return view('books.edit', compact('book'));
    }

    // 书籍执行编辑
    public function update($id, Request $request)
    {
        $book = Book::findOrFail($id);

        $rules = [
            'title' => 'required|min:2',
            'author' => 'required|min:3',
            'status' => 'required'
        ];

        if (!empty($request->image)) {
            $rules['image'] = 'required|image|mimes:jpeg,png,jpg|max:2048';
        }

        // 验证
        $validator = Validator::make($request->all(), $rules);

        // 如果验证失败,我们将返回错误
        if ($validator->fails()) {
            return redirect()->route('books.edit',$book->id)->withErrors($validator)->withInput();
        }

        // 执行书籍编辑
        $book->title = $request->title;
        $book->author = $request->author;
        $book->description = $request->description;
        $book->status = $request->status;
        $book->save();

        // 这里上传图片
        if (!empty($request->image)) {

            // 在这里删除旧图片
            File::delete(public_path('uploads/profile/' . $book->image));
            File::delete(public_path('uploads/profile/thumb/' . $book->image));

            $image = $request->image;
            $ext = $image->getClientOriginalExtension(); // 获取原图片名称
            $image_name = time() . '.' . $ext; // 生成时间戳唯一名称
            $image->move(public_path('uploads/books'), $image_name);

            $book->image = $image_name;
            $book->save();

            // 创建缩略图
            $manager = new ImageManager(Driver::class);
            $img = $manager->read(public_path('uploads/books/' . $image_name));

            $img->resize(990); // 调整图片大小
            $img->save(public_path('uploads/books/thumb/' . $image_name)); // 存放在uploads/books/thumb
        }

        return redirect()->route('books.index')->with('sucsess', '编辑书籍成功~~');
    }

    // 书籍删除
    public function destroy(Request $request)
    {
        $book = Book::find($request->id);

        if ($book == null) {
            session()->flash('error','找不到书');
            return response()->json([
                'success' => false,
                'message' => '找不到书'
            ]);
        } else {
            File::delete(public_path('uploads/books/' . $book->image));
            File::delete(public_path('uploads/books/thumb/' . $book->image));
            $book->delete();

            session()->flash('success','图书删除成功');
            return response()->json([
                'success' => true,
                'message' => '图书删除成功'
            ]);
        }
    }

}

书籍模型创建

php artisan make:model Book

app/Models/Book

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    protected $fillable = [
        'title',
        'author',
        'description',
        'status',
    ];
}

模版创建

php artisan make:view books\list

resources/view/books/list.blade.php

@extends('layouts.app')

@section('title', '书籍首页')

@section('content')
    <div class="container">
        <div class="row my-5">
            <div class="col-md-3">
                <div class="card border-0 shadow-lg">
                    <div class="card-header  text-white">
                        欢迎, {{ Auth::user()->name }}
                    </div>
                    <div class="card-body">
                        <div class="text-center mb-3">
                            @if(Auth::user()->image !="")
                                <img src="{{ asset('uploads/profile/thumb/' .Auth::user()->image) }}"
                                     class="img-fluid rounded-circle" alt="">
                            @endif
                        </div>
                        <div class="h5 text-center">
                            <strong>{{ Auth::user()->name }}</strong>
                            <p class="h6 mt-2 text-muted">5 Reviews</p>
                        </div>
                    </div>
                </div>
                <div class="card border-0 shadow-lg mt-3">
                    <div class="card-header  text-white">
                        菜单
                    </div>
                    <div class="card-body sidebar">
                        {{-- 菜单选项 --}}
                        @include('layouts.sidebar')
                    </div>
                </div>
            </div>
            <div class="col-md-9">

                {{-- 表单验证文件 --}}
                @include('layouts.message')

                <div class="card border-0 shadow">
                    <div class="card-header  text-white">
                        书籍
                    </div>
                    <div class="card-body pb-0">

                        <div class="d-flex justify-content-between">
                            <a href="{{ route('books.create') }}" class="btn btn-primary">新增书籍</a>
                            <form action="" method="get">
                                <div class="d-flex">

                                    <input type="text" class="form-control" name="keyword"
                                           value="{{ Request::get('keyword') }}" placeholder="请您输入搜索词">
                                    <button type="submit" class="btn btn-primary">Search</button>
                                    <a href="{{ route('books.index') }}" class="btn btn-secondary ms-2"></a>
                                </div>
                            </form>
                        </div>
                        <table class="table  table-striped mt-3">
                            <thead class="table-dark">
                            <tr>
                                <th>标题</th>
                                <th>作者</th>
                                <th>评级</th>
                                <th>状态</th>
                                <th width="150">操作</th>
                            </tr>
                            <tbody>
                            @if($books->isNotEmpty())
                                {{--将空字符进行判断,有空字符也会判断为不空--}}
                                @foreach($books as $book)
                                    <tr>
                                        <td>{{ $book->title }}</td>
                                        <td>{{ $book->author }}</td>
                                        <td>3.0 (3 Reviews)</td>
                                        <td>
                                            @if($book->status == 1 )
                                                <span class="text-success">Actice</span>
                                            @else
                                                <span class="text-danger">Block</span>
                                            @endif
                                        </td>
                                        <td>
                                            <a href="#" class="btn btn-success btn-sm"><i
                                                    class="fa-regular fa-star"></i></a>
                                            <a href="{{ route('books.edit',$book->id) }}"
                                               class="btn btn-primary btn-sm"><i
                                                    class="fa-regular fa-pen-to-square"></i>
                                            </a>
                                            <a href="#" onclick="deleteBook({{ $book->id }});"
                                               class="btn btn-danger btn-sm"><i
                                                    class="fa-solid fa-trash"></i></a>
                                        </td>
                                    </tr>
                                @endforeach
                            @else
                                <tr>
                                    <td colspan="5">
                                        未找到书籍~~
                                    </td>
                                </tr>
                            @endif
                            </tbody>
                            </thead>
                        </table>
                        @if($books->isNotEmpty())
                            {{--分页--}}
                            {{$books->links()}}
                        @endif
                    </div>

                </div>
            </div>
        </div>
        @endsection

        @section('script')
            <script>
                function deleteBook(id) {
                    if (confirm("您确定要删除书籍么")) {
                        $.ajax({
                            url: '{{ route("books.destroy") }}',
                            type: 'delete',
                            data: {id: id},
                            headers: {
                                'X-CSRF-TOKEN': '{{ csrf_token()}}'
                            },
                            success: function (response) {
                                window.location.href = '{{ route("books.index") }}';
                            }
                        });
                    }
                }
            </script>
@endsection

resources/view/books/create.blade.php

@extends('layouts.app')

@section('title', '新增书籍')

@section('content')
    <div class="container">
        <div class="row my-5">
            <div class="col-md-3">
                <div class="card border-0 shadow-lg">
                    <div class="card-header  text-white">
                        欢迎, {{ Auth::user()->name }}
                    </div>
                    <div class="card-body">
                        <div class="text-center mb-3">
                            @if(Auth::user()->image !="")
                                <img src="{{ asset('uploads/profile/thumb/' .Auth::user()->image) }}"
                                     class="img-fluid rounded-circle" alt="">
                            @endif
                        </div>
                        <div class="h5 text-center">
                            <strong>{{ Auth::user()->name }}</strong>
                            <p class="h6 mt-2 text-muted">5 Reviews</p>
                        </div>
                    </div>
                </div>
                <div class="card border-0 shadow-lg mt-3">
                    <div class="card-header  text-white">
                        菜单
                    </div>
                    <div class="card-body sidebar">
                        {{-- 菜单选项 --}}
                        @include('layouts.sidebar')
                    </div>
                </div>
            </div>
            <div class="col-md-9">

                {{-- 表单验证文件 --}}
                @include('layouts.message')

                <div class="card border-0 shadow">
                    <div class="card-header  text-white">
                        新建书籍
                    </div>
                    <div class="card-body">
                        <form action="{{ route('books.store') }}" method="post" enctype="multipart/form-data">
                            @csrf

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

                                @error('title')
                                <p class="invalid-feedback">{{ $message }}</p>
                                @enderror

                            </div>
                            <div class="mb-3">
                                <label for="author" class="form-label">作者</label>
                                <input type="text" class="form-control @error('author') is-invalid @enderror"
                                       placeholder="请输入作者" name="author" id="author" value="{{ old('author') }}" />

                                @error('author')
                                <p class="invalid-feedback">{{ $message }}</p>
                                @enderror

                            </div>

                            <div class="mb-3">
                                <label for="author" class="form-label">描述</label>
                                <textarea name="description" id="description" class="form-control" placeholder="请输入描述"
                                          cols="30" rows="5">{{ old('description') }}</textarea>
                            </div>

                            <div class="mb-3">
                                <label for="Image" class="form-label">封面</label>
                                <input type="file" class="form-control @error('image') is-invalid @enderror"
                                       name="image"
                                       id="image"/>

                                @error('image')
                                <p class="invalid-feedback">{{ $message }}</p>
                                @enderror

                            </div>

                            <div class="mb-3">
                                <label for="author" class="form-label">状态</label>
                                <select name="status" id="status" class="form-control">
                                    <option value="1">Active</option>
                                    <option value="0">Block</option>
                                </select>
                            </div>
                            <button class="btn btn-primary mt-2">新增</button>
                        </form>
                    </div>
                </div>

            </div>
        </div>
    </div>
@endsection

resources/view/books/edit.blade.php

@extends('layouts.app')

@section('title', '编辑书籍')

@section('content')
    <div class="container">
        <div class="row my-5">
            <div class="col-md-3">
                <div class="card border-0 shadow-lg">
                    <div class="card-header  text-white">
                        欢迎, {{ Auth::user()->name }}
                    </div>
                    <div class="card-body">
                        <div class="text-center mb-3">
                            @if(Auth::user()->image !="")
                                <img src="{{ asset('uploads/profile/thumb/' .Auth::user()->image) }}"
                                     class="img-fluid rounded-circle" alt="">
                            @endif
                        </div>
                        <div class="h5 text-center">
                            <strong>{{ Auth::user()->name }}</strong>
                            <p class="h6 mt-2 text-muted">5 Reviews</p>
                        </div>
                    </div>
                </div>
                <div class="card border-0 shadow-lg mt-3">
                    <div class="card-header  text-white">
                        菜单
                    </div>
                    <div class="card-body sidebar">
                        {{-- 菜单选项 --}}
                        @include('layouts.sidebar')
                    </div>
                </div>
            </div>
            <div class="col-md-9">

                {{-- 表单验证文件 --}}
                @include('layouts.message')

                <div class="card border-0 shadow">
                    <div class="card-header  text-white">
                        编辑书籍
                    </div>
                    <div class="card-body">
                        <form action="{{ route('books.update',$book->id) }}" method="post"
                              enctype="multipart/form-data">
                            @csrf

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

                                @error('title')
                                <p class="invalid-feedback">{{ $message }}</p>
                                @enderror

                            </div>
                            <div class="mb-3">
                                <label for="author" class="form-label">作者</label>
                                <input type="text" class="form-control @error('author') is-invalid @enderror"
                                       placeholder="请输入作者" name="author" id="author"
                                       value="{{ old('author',$book->author) }}"/>

                                @error('author')
                                <p class="invalid-feedback">{{ $message }}</p>
                                @enderror

                            </div>

                            <div class="mb-3">
                                <label for="author" class="form-label">描述</label>
                                <textarea name="description" id="description" class="form-control" placeholder="请输入描述"
                                          cols="30" rows="5">{{ old('description',$book->description) }}</textarea>
                            </div>

                            <div class="mb-3">
                                <label for="Image" class="form-label">封面</label>
                                <input type="file" class="form-control @error('image') is-invalid @enderror"
                                       name="image"
                                       id="image"/>

                                @error('image')
                                <p class="invalid-feedback">{{ $message }}</p>
                                @enderror

                                @if(!empty($book->image))
                                    <img class="w-25 my-3" src="{{ asset('uploads/books/thumb/' .$book->image) }}"
                                         alt="">
                                @endif

                            </div>

                            <div class="mb-3">
                                <label for="author" class="form-label">状态</label>
                                <select name="status" id="status" class="form-control">
                                    <option value="1" {{ ($book->status == 1)? 'selected' : '' }}>Active</option>
                                    <option value="0" {{ ($book->status == 0)? 'selected' : '' }}>Block</option>
                                </select>
                            </div>
                            <button class="btn btn-primary mt-2">更新</button>
                        </form>
                    </div>
                </div>

            </div>
        </div>
    </div>
@endsection

App/Providers/AppServiceProvider分页器改成使用Bootstrap 5

public function register(): void
{
    // 分页器改成使用Bootstrap 5
    Paginator::useBootstrapFive();
}