Laravel 11 书评网1--登录注册布局与控制器逻辑

76 阅读3分钟

书评网设置

.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>