书评网设置
.env修改数据库类型
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=book
DB_USERNAME=root
DB_PASSWORD=
迁移文件
0001_01_01_000000_create_users_table.php 添加$table->enum('role',['user','admin']);
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->enum('role',['user','admin'])->default('user');
});
}
执行迁移
php artisan migrate
生产迁移文件
php artisan make:migration alter_users_table
编写迁移文件
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('image')->nullable()->after('email');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('image');
});
}
执行迁移
php artisan migrate
Intervention Image是最流行的开源PHP图像处理库,裁剪图片大小作用
composer require intervention/image
创建账户控制器 AccountController
php artisan make:controller AccountController
Http/controllers/AccountController.php
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;
class AccountController extends Controller
{
// 注册
public function register()
{
return view('account.register');
}
// 执行注册
public function processRegister(Request $request)
{
// 验证
$validator = Validator::make($request->all(), [
'name' => 'required|max:10',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|max:6',
'password_confirmation' => 'required'
]);
// 如果验证失败,我们将返回错误
if ($validator->fails()) {
return redirect()->route('account.register')->withErrors($validator)->withInput();
}
// 执行注册
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = Hash::make($request->password);
$user->save();
return redirect()->route('account.login')->with('sucsess', '恭喜您注册成功~~');
}
// 登录
public function login()
{
return view('account.login');
}
// 执行登录
public function authenticate(Request $request)
{
// 验证
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'password' => 'required',
]);
// 如果验证失败,我们将返回错误
if ($validator->fails()) {
return redirect()->route('account.login')->withErrors($validator)->withInput();
}
if (Auth::attempt(['email' => $request->email, 'password' => $request->password])) {
// 认证通过
return redirect()->route('account.profile');
} else {
// 认证失败
return redirect()->route('account.login')->with('error', '电子邮件/密码不正确');
}
}
// 个人资料页
public function profile()
{
$user = User::find(Auth::user()->id);
return view('account.profile', compact('user'));
}
// 个人资料更新
public function updateProfile(Request $request)
{
$rules = [
'name' => 'required|max:10',
'email' => 'required|email|unique:users,email,' . Auth::user()->id . ',id',
// 'email' => 'required|email|unique:users,email',
];
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('account.profile')->withErrors($validator)->withInput();
}
// 执行个人资料更新
$user = User::find(Auth::user()->id);
$user->name = $request->name;
$user->email = $request->email;
$user->save();
// 这里上传图片
if (!empty($request->image)) {
// 在这里删除旧图片
File::delete(public_path('uploads/profile/' . $user->image));
File::delete(public_path('uploads/profile/thumb/' . $user->image));
$image = $request->image;
$ext = $image->getClientOriginalExtension(); // 获取原图片名称
$image_name = time() . '.' . $ext; // 生成时间戳唯一名称
$image->move(public_path('uploads/profile'), $image_name);
$user->image = $image_name;
$user->save();
// 创建缩略图
$manager = new ImageManager(Driver::class);
$img = $manager->read(public_path('uploads/profile/' . $image_name));
$img->cover(150, 150); // 裁剪图片
$img->save( public_path('uploads/profile/thumb/' . $image_name)); // 存放在uploads/profile/thumb
}
return redirect()->route('account.profile')->with('sucsess', '个人资料更新成功~~');
}
// 账号退出
public function logout()
{
Auth::logout();
return redirect()->route('account.login');
}
}
路由定义
Route::group(['prefix' => 'account'], function () {
Route::group(['middleware' => 'guest'], function () {
// 注册
Route::get('register', [\App\Http\Controllers\AccountController::class, 'register'])
->name('account.register');
// 执行注册
Route::post('register', [\App\Http\Controllers\AccountController::class, 'processRegister'])
->name('account.processRegister');
// 登录
Route::get('login', [\App\Http\Controllers\AccountController::class, 'login'])
->name('account.login');
// 执行登录
Route::post('login', [\App\Http\Controllers\AccountController::class, 'authenticate'])
->name('account.authenticate');
});
Route::group(['middleware' => 'auth'], function () {
// 个人资料页
Route::get('profile', [\App\Http\Controllers\AccountController::class, 'profile'])
->name('account.profile');
// 个人资料执行更新
Route::post('update-profile', [\App\Http\Controllers\AccountController::class, 'updateProfile'])
->name('account.updateProfile');
// 账号退出
Route::get('logout', [\App\Http\Controllers\AccountController::class, 'logout'])
->name('account.logout');
});
bootstrap/app.php 定义登录后跳转到个人主页,没有登录的跳转登录页面
->withMiddleware(function (Middleware $middleware) {
$middleware->redirectTo(
guests: 'account/login',
users: 'account/profile'
);
})
前端模版布局
resources/views/layouts/app.blade.php
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name')}} - @yield('title')</title>
<link rel="stylesheet" href="https://unpkg.com/bootstrap@5.3.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
</head>
<body class="bg-light">
<div class="container-fluid shadow-lg header">
<div class="container">
<div class="d-flex justify-content-between">
<h1 class="text-center"><a href="index.html" class="h3 text-white text-decoration-none">Book Review App</a>
</h1>
<div class="d-flex align-items-center navigation">
@if(Auth::check())
<a href="{{ route('account.profile') }}" class="text-white">{{ Auth::user()->name }}</a>
@else
<a href="{{ route('account.login') }}" class="text-white">登录</a>
<a href="{{ route('account.register') }}" class="text-white ps-2">注册</a>
@endif
</div>
</div>
</div>
</div>
@yield('content')
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
crossorigin="anonymous"></script>
</body>
</html>
resources/views/account/register.blade.php
@extends('layouts.app')
@section('title', '注册')
@section('content')
<section class=" p-3 p-md-4 p-xl-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-md-9 col-lg-7 col-xl-6 col-xxl-5">
<div class="card border border-light-subtle rounded-4">
<div class="card-body p-3 p-md-4 p-xl-5">
<div class="row">
<div class="col-12">
<div class="mb-5">
<h4 class="text-center">在这里注册</h4>
</div>
</div>
</div>
<form action="{{ route('account.processRegister') }}" method="post">
@csrf
<div class="row gy-3 overflow-hidden">
<div class="col-12">
<div class="form-floating mb-3">
<input type="text" class="form-control @error('name') is-invalid @enderror"
name="name" id="name"
placeholder="Name">
<label for="text" class="form-label">昵称</label>
@error('name')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
<div class="col-12">
<div class="form-floating mb-3">
<input type="text" class="form-control @error('email') is-invalid @enderror"
name="email" id="email"
placeholder="name@example.com">
<label for="text" class="form-label">电子邮箱</label>
@error('email')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
<div class="col-12">
<div class="form-floating mb-3">
<input type="password"
class="form-control @error('password') is-invalid @enderror"
name="password" id="password"
value="" placeholder="Password">
<label for="password" class="form-label">密码</label>
@error('password')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
<div class="col-12">
<div class="form-floating mb-3">
<input type="password"
class="form-control @error('password_confirmation') is-invalid @enderror"
name="password_confirmation"
id="password_confirmation" value="" placeholder="Confirm Password">
<label for="password" class="form-label">确认密码</label>
@error('password_confirmation')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
<div class="col-12">
<div class="d-grid">
<button class="btn bsb-btn-xl btn-primary py-3" type="submit">立即注册</button>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-12">
<hr class="mt-5 mb-4 border-secondary-subtle">
<div class="d-flex gap-2 gap-md-4 flex-column flex-md-row justify-content-center">
<a href="{{ route('account.login') }}" class="link-secondary text-decoration-none">点击此处登录</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
@endsection
resources/views/account/login.blade.php
@extends('layouts.app')
@section('title', '登录')
@section('content')
<section class=" p-3 p-md-4 p-xl-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-md-9 col-lg-7 col-xl-6 col-xxl-5">
{{-- 表单验证文件 --}}
@include('layouts.message')
<div class="card border border-light-subtle rounded-4">
<div class="card-body p-3 p-md-4 p-xl-5">
<div class="row">
<div class="col-12">
<div class="mb-5">
<h4 class="text-center">在这里登录</h4>
</div>
</div>
</div>
<form action="{{ route('account.authenticate') }}" method="post">
@csrf
<div class="row gy-3 overflow-hidden">
<div class="col-12">
<div class="form-floating mb-3">
<input value="{{ old('email') }}" type="text"
class="form-control @error('email') is-invalid @enderror"
name="email" id="email"
placeholder="name@example.com">
<label for="email" class="form-label">电子邮箱</label>
@error('email')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
<div class="col-12">
<div class="form-floating mb-3">
<input type="password"
class="form-control @error('password') is-invalid @enderror"
name="password" id="password"
value="" placeholder="Password">
<label for="password" class="form-label">密码</label>
@error('password')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
<div class="col-12">
<div class="d-grid">
<button class="btn bsb-btn-xl btn-primary py-3" type="submit">现在登录
</button>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-12">
<hr class="mt-5 mb-4 border-secondary-subtle">
<div class="d-flex gap-2 gap-md-4 flex-column flex-md-row justify-content-center">
<a href="{{ route('account.processRegister') }}"
class="link-secondary text-decoration-none">创建账号</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
@endsection
resources/views/account/profile.blade.php
@extends('layouts.app')
@section('title', '个人资料')
@section('content')
<div class="container">
<div class="row my-5">
<div class="col-md-3">
{{-- 侧边栏 --}}
@include('layouts.sidebar')
</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('account.updateProfile') }}" method="post" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="name" class="form-label">用户名</label>
<input type="text" value="{{ old('name',$user->name) }}"
class="form-control @error('name') is-invalid @enderror" placeholder="Name"
name="name" id=""/>
@error('name')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
<div class="mb-3">
<label for="name" class="form-label">电子邮箱</label>
<input type="text" value="{{ old('email',$user->email) }}"
class="form-control @error('email') is-invalid @enderror" placeholder="Email"
name="email" id="email"/>
@error('email')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
<div class="mb-3">
<label for="image" class="form-label">头像</label>
<input type="file" name="image" id="image"
class="form-control @error('image') is-invalid @enderror">
@error('image')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
@if(Auth::user()->image !="")
<img src="{{ asset('uploads/profile/thumb/' .Auth::user()->image) }}"
class="img-fluid mt-4" alt="">
@endif
</div>
<button class="btn btn-primary mt-2">更新</button>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/layouts/sidebar.blade.php
<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">
<ul class="nav flex-column">
{{-- 如果角色为管理员,则看到书籍和评论 --}}
@if(Auth::user()->role == 'admin')
<li class="nav-item">
<a href="{{ route('books.index') }}">书籍</a>
</li>
<li class="nav-item">
<a href="{{ route('account.reviews') }}">评论</a>
</li>
@endif
<li class="nav-item">
<a href="profile.html">Profile</a>
</li>
<li class="nav-item">
<a href="{{ route('account.myReviews') }}">我的评论</a>
</li>
<li class="nav-item">
<a href="change-password.html">更改密码</a>
</li>
<li class="nav-item">
<a href="{{ route('account.logout') }}">退出</a>
</li>
</ul>
</div>
</div>