创建书籍迁移文件
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();
}