摘要 Laravel 12 是目前最流行的 PHP Web 框架之一,以其优雅的语法、强大的功能和完善的生态系统而闻名。本教程基于 Laravel 12 版本,详细介绍了从环境搭建、项目初始化、路由和控制器、视图到数据库操作的完整 Web 开发流程,帮助初学者快速掌握 Laravel 框架的核心概念和实战技能,为 Web 开发之旅打下坚实的基础。
Laravel 12 教程 - Web 开发实战入门 前言 欢迎阅读《Laravel 12 教程 - Web 开发实战入门》!本教程基于最新的 Laravel 12 版本,旨在帮助初学者快速掌握 Laravel 框架的核心概念和实战技能,为您的 Web 开发之旅打下坚实的基础。Laravel 12 作为 PHP 生态中最流行的 Web 框架之一,提供了简洁优雅的语法、强大的功能和完善的生态系统,是现代 Web 开发的理想选择。
为什么选择 Laravel 12? Laravel 12 是目前最流行的 PHP Web 框架之一,它以优雅的语法、强大的功能和完善的生态系统而闻名。选择 Laravel 12 的原因包括:
简洁优雅的语法 :Laravel 12 提供了简洁明了的语法,让代码更加易读和易维护丰富的功能 :Laravel 12 内置了路由、控制器、视图、数据库操作、认证等全套 Web 开发所需的功能强大的生态系统 :Laravel 12 拥有丰富的扩展包和活跃的社区支持现代化的开发体验 :Laravel 12 支持依赖注入、服务容器、中间件等现代 PHP 开发特性完善的文档 :Laravel 12 提供了详尽的官方文档,学习曲线平缓性能优化 :Laravel 12 在性能方面进行了多项优化,提供更快的响应速度安全性 :Laravel 12 内置了多种安全特性,如 CSRF 保护、密码加密等可扩展性 :Laravel 12 的模块化设计使其易于扩展和定制本教程的目标 通过本教程的学习,您将能够:
搭建 Laravel 12 开发环境 理解 Laravel 12 的核心概念和工作原理 掌握 Laravel 12 的基本功能和使用方法 开发一个完整的 Laravel 12 Web 应用 将 Laravel 12 应用部署到生产环境 运用 Laravel 12 的最佳实践进行 Web 开发 解决 Laravel 12 开发中常见的问题 为进一步学习 Laravel 12 高级特性打下基础 前置知识 本教程适合具有以下基础的读者:
基本的 PHP 编程知识 基本的 HTML、CSS 和 JavaScript 知识 基本的数据库概念 如果您是完全的初学者,建议先学习一些 PHP 和 Web 开发的基础知识,再开始本教程的学习。
教程结构 本教程分为以下几个部分:
环境搭建 :安装 PHP、Composer 和 Laravel 12项目初始化 :创建 Laravel 12 项目和了解目录结构路由和控制器 :学习 Laravel 12 的路由系统和控制器视图 :学习 Laravel 12 的 Blade 模板引擎数据库操作 :学习 Laravel 12 的数据库操作方法表单处理 :学习 Laravel 12 的表单验证和处理认证系统 :学习 Laravel 12 的用户认证系统文件上传和存储 :学习 Laravel 12 的文件处理功能部署 :学习如何部署 Laravel 12 应用现在,让我们开始 Laravel 的学习之旅吧!
1. Laravel 12 环境搭建 要开始使用 Laravel 12,我们需要搭建一个合适的开发环境。Laravel 12 需要以下软件:
PHP 8.2 或更高版本 Composer(PHP 依赖管理工具) 数据库(MySQL、PostgreSQL、SQLite 等) Laravel 12 对环境有特定的要求,确保您的系统满足这些要求,以便顺利运行 Laravel 12 应用。
1.1 Laravel 12 PHP 安装要求 Laravel 12 要求 PHP 8.2 或更高版本,并且需要安装以下 PHP 扩展:
PHP CLI PHP MBString PHP XML PHP MySQL PHP CURL PHP GD PHP ZIP Windows 系统 使用 XAMPP
访问 XAMPP 官网 下载最新版本的 XAMPP 运行安装程序,选择安装 PHP 8.2 或更高版本 安装完成后,启动 XAMPP 控制面板,启动 Apache 服务 使用 WAMP
访问 WAMP 官网 下载最新版本的 WAMP 运行安装程序,选择安装 PHP 8.2 或更高版本 安装完成后,启动 WAMP 服务 macOS 系统 使用 Homebrew
1 2 3 4 5 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) " brew install php
使用 MAMP
访问 MAMP 官网 下载最新版本的 MAMP 运行安装程序,选择安装 PHP 8.2 或更高版本 安装完成后,启动 MAMP 服务 Linux 系统 Ubuntu/Debian
1 2 3 4 5 sudo apt updatesudo apt install php8.2 php8.2-cli php8.2-mbstring php8.2-xml php8.2-mysql php8.2-curl php8.2-gd php8.2-zip
CentOS/RHEL
1 2 3 4 5 6 7 8 9 10 11 sudo yum install epel-releasesudo yum install https://rpms.remirepo.net/enterprise/remi-release-8.rpmsudo dnf module enable php:remi-8.2sudo yum install php php-cli php-mbstring php-xml php-mysqlnd php-curl php-gd php-zip
1.2 Laravel 12 Composer 安装 Composer 是 PHP 的依赖管理工具,Laravel 12 依赖于 Composer 来管理其依赖项。确保安装最新版本的 Composer 以获得最佳的 Laravel 12 开发体验。
Windows 系统 访问 Composer 官网 下载 Composer-Setup.exe 运行安装程序,按照提示完成安装 安装完成后,打开命令提示符,运行 composer --version 验证安装成功 macOS/Linux 系统 1 2 3 4 5 6 7 8 curl -sS https://getcomposer.org/installer | php sudo mv composer.phar /usr/local/bin/composercomposer --version
安装完成后,Composer 将成为 Laravel 12 项目管理的重要工具,用于安装依赖、创建项目和更新框架。
1.3 Laravel 12 安装 Laravel 12 提供了多种安装方式,我们推荐使用 Composer 或 Laravel Installer。
使用 Composer 创建 Laravel 12 项目 1 2 3 4 5 composer create-project laravel/laravel:^12.0 project-name cd project-name
使用 Laravel Installer 安装 Laravel 12 安装 Laravel Installer
1 composer global require laravel/installer
添加 Composer 全局目录到 PATH
Windows:将 %APPDATA%\Composer\vendor\bin 添加到系统环境变量 PATH macOS/Linux:将 ~/.composer/vendor/bin 添加到 ~/.bashrc 或 ~/.zshrc 文件中 创建 Laravel 12 项目
1 2 3 4 laravel new project-name cd project-name
Laravel 12 安装完成后,您就可以开始构建现代化的 Web 应用了。
1.4 Laravel 12 验证安装 安装完成后,我们可以通过以下命令验证 Laravel 12 项目是否创建成功:
然后在浏览器中访问 http://localhost:8000,如果看到 Laravel 12 的欢迎页面,则说明安装成功。Laravel 12 的欢迎页面通常会显示当前 Laravel 版本信息和一些快速开始的链接。
1.5 Laravel 12 数据库配置 Laravel 12 默认使用 MySQL 作为数据库,但也支持 PostgreSQL、SQLite 等其他数据库。我们需要配置数据库连接以确保 Laravel 12 应用能够正常访问数据库。
创建数据库
使用 MySQL 命令行或 phpMyAdmin 创建一个新的数据库 配置 Laravel 12 数据库连接
1 2 3 4 5 6 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=your_database_name DB_USERNAME=your_database_username DB_PASSWORD=your_database_password
Laravel 12 数据库配置完成后,您就可以开始使用 Laravel 的数据库功能了,包括数据库迁移、Eloquent ORM 和查询构建器等。
现在,我们的 Laravel 12 开发环境已经搭建完成,接下来我们将创建一个新的 Laravel 12 项目并了解其目录结构。
2. Laravel 12 项目初始化和目录结构 2.1 Laravel 12 项目创建 我们已经在环境搭建章节中介绍了两种创建 Laravel 12 项目的方法,这里再简要回顾一下:
使用 Composer 创建 Laravel 12 项目 1 2 3 4 5 composer create-project laravel/laravel:^12.0 project-name cd project-name
使用 Laravel Installer 创建 Laravel 12 项目 1 2 3 4 5 laravel new project-name cd project-name
2.2 Laravel 12 目录结构 Laravel 12 项目的目录结构组织得非常清晰,遵循了现代 PHP 应用的最佳实践。下面是 Laravel 12 的主要目录结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 project-name/ ├── app/ # Laravel 12 应用核心代码 │ ├── Console/ # Laravel 12 命令行工具 │ ├── Exceptions/ # Laravel 12 异常处理 │ ├── Http/ # Laravel 12 HTTP 相关代码 │ │ ├── Controllers/ # Laravel 12 控制器 │ │ ├── Middleware/ # Laravel 12 中间件 │ │ └── Requests/ # Laravel 12 请求验证 │ ├── Models/ # Laravel 12 数据模型 │ ├── Providers/ # Laravel 12 服务提供者 │ └── View/ # Laravel 12 视图相关代码 ├── bootstrap/ # Laravel 12 引导文件 ├── config/ # Laravel 12 配置文件 ├── database/ # Laravel 12 数据库相关文件 │ ├── factories/ # Laravel 12 数据工厂 │ ├── migrations/ # Laravel 12 数据库迁移 │ └── seeders/ # Laravel 12 数据填充 ├── public/ # Laravel 12 公共目录(网站根目录) │ ├── assets/ # Laravel 12 静态资源 │ └── index.php # Laravel 12 入口文件 ├── resources/ # Laravel 12 资源文件 │ ├── css/ # Laravel 12 CSS 文件 │ ├── js/ # Laravel 12 JavaScript 文件 │ └── views/ # Laravel 12 视图文件 ├── routes/ # Laravel 12 路由文件 ├── storage/ # Laravel 12 存储目录 │ ├── app/ # Laravel 12 应用存储 │ ├── framework/ # Laravel 12 框架存储 │ └── logs/ # Laravel 12 日志文件 ├── tests/ # Laravel 12 测试文件 ├── vendor/ # Laravel 12 依赖包 ├── .env # Laravel 12 环境变量 ├── .env.example # Laravel 12 环境变量示例 ├── composer.json # Laravel 12 Composer 配置 ├── package.json # Laravel 12 NPM 配置 ├── phpunit.xml # Laravel 12 PHPUnit 配置 ├── vite.config.js # Laravel 12 Vite 配置 └── artisan # Laravel 12 Artisan 命令行工具
Laravel 12 的目录结构设计合理,便于开发者组织和管理代码,同时也符合现代 PHP 应用的最佳实践。
2.3 Laravel 12 重要目录和文件详解 app 目录 app 目录包含了 Laravel 12 应用的核心代码,是我们开发的主要场所。
Console/ :包含 Laravel 12 自定义的 Artisan 命令Exceptions/ :包含 Laravel 12 异常处理类Http/ :包含 Laravel 12 HTTP 相关的代码,如控制器、中间件和请求验证Models/ :包含 Laravel 12 Eloquent 模型类Providers/ :包含 Laravel 12 服务提供者类,用于注册服务和引导应用View/ :包含 Laravel 12 视图相关的代码,如视图组件config 目录 config 目录包含了 Laravel 12 应用的配置文件,如数据库配置、邮件配置、缓存配置等。
database 目录 database 目录包含了 Laravel 12 数据库相关的文件:
factories/ :包含 Laravel 12 数据工厂类,用于生成测试数据migrations/ :包含 Laravel 12 数据库迁移文件,用于定义数据库表结构seeders/ :包含 Laravel 12 数据填充类,用于填充初始数据public 目录 public 目录是 Laravel 12 网站的根目录,包含了入口文件 index.php 和静态资源。
resources 目录 resources 目录包含了 Laravel 12 应用的资源文件:
css/ :包含 Laravel 12 CSS 文件js/ :包含 Laravel 12 JavaScript 文件views/ :包含 Laravel 12 Blade 模板文件routes 目录 routes 目录包含了 Laravel 12 应用的路由定义文件:
web.php :定义 Laravel 12 Web 路由api.php :定义 Laravel 12 API 路由console.php :定义 Laravel 12 控制台路由channels.php :定义 Laravel 12 广播频道storage 目录 storage 目录包含了 Laravel 12 应用的存储文件:
app/ :用于存储 Laravel 12 应用生成的文件framework/ :用于存储 Laravel 12 框架生成的文件,如缓存logs/ :用于存储 Laravel 12 日志文件vendor 目录 vendor 目录包含了 Laravel 12 Composer 安装的依赖包。
.env 文件 .env 文件包含了 Laravel 12 应用的环境变量,如数据库连接信息、邮件配置等。这个文件不应该提交到版本控制系统中。
artisan 文件 artisan 是 Laravel 12 的命令行工具,用于执行各种命令,如生成控制器、运行迁移等。
2.4 Laravel 12 配置文件 Laravel 12 的配置文件位于 config 目录中,采用 PHP 数组格式,易于理解和修改。下面是一些 Laravel 12 重要的配置文件:
config/app.php Laravel 12 应用的主要配置文件,包含应用名称、时区、语言等配置。
config/database.php Laravel 12 数据库配置文件,包含数据库连接信息。
config/mail.php Laravel 12 邮件配置文件,包含邮件发送配置。
config/cache.php Laravel 12 缓存配置文件,包含缓存驱动配置。
config/session.php Laravel 12 会话配置文件,包含会话驱动配置。
Laravel 12 的配置文件设计合理,便于开发者根据项目需求进行定制和修改。
2.5 Laravel 12 环境变量 Laravel 12 使用 .env 文件来存储环境变量,这些变量可以在配置文件中使用,便于在不同环境中使用不同的配置。下面是一些 Laravel 12 重要的环境变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # Laravel 12 应用配置 APP_NAME=Laravel APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://localhost # Laravel 12 数据库配置 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD= # Laravel 12 邮件配置 MAIL_MAILER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS=null MAIL_FROM_NAME="${APP_NAME}"
Laravel 12 的环境变量设计使得应用在不同环境(如开发、测试、生产)中可以使用不同的配置,提高了应用的可移植性和安全性。
2.6 Laravel 12 Artisan 命令行工具 Artisan 是 Laravel 12 提供的命令行工具,非常强大和灵活,是 Laravel 开发中的重要工具。下面是一些 Laravel 12 常用的 Artisan 命令:
查看所有 Laravel 12 命令 生成 Laravel 12 控制器 1 php artisan make:controller ControllerName
生成 Laravel 12 模型 1 php artisan make:model ModelName
生成 Laravel 12 迁移 1 php artisan make:migration create_table_name
运行 Laravel 12 迁移 生成 Laravel 12 数据填充 1 php artisan make:seeder SeederName
运行 Laravel 12 数据填充 启动 Laravel 12 开发服务器 Laravel 12 Artisan 命令行工具提供了丰富的命令,大大提高了开发效率,是 Laravel 12 开发中不可或缺的工具。
2.7 Laravel 12 项目初始化示例 现在,让我们创建一个简单的 Laravel 12 项目,来熟悉一下整个流程:
创建 Laravel 12 项目
1 2 composer create-project laravel/laravel:^12.0 blog cd blog
启动 Laravel 12 开发服务器
访问 Laravel 12 应用 在浏览器中访问 http://localhost:8000,你应该能看到 Laravel 12 的欢迎页面。
查看 Laravel 12 目录结构 浏览 Laravel 12 项目的目录结构,了解各个目录和文件的作用。
通过这个简单的 Laravel 12 项目初始化示例,你可以快速熟悉 Laravel 12 的基本使用流程,为后续的学习打下基础。
现在,我们已经了解了 Laravel 12 项目的初始化过程和目录结构,接下来我们将学习 Laravel 12 的路由系统和控制器。
3. Laravel 12 路由和控制器 3.1 Laravel 12 路由基础 路由是 Laravel 12 应用的入口点,它定义了 URL 如何映射到应用的功能。Laravel 12 的路由定义在 routes 目录下的文件中,主要包括 web.php 和 api.php。Laravel 12 的路由系统非常强大,支持多种路由类型和参数。
Laravel 12 基本路由 在 Laravel 12 的 routes/web.php 文件中,我们可以定义基本的路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 use Illuminate \Support \Facades \Route ;Route ::get ('/' , function () { return view ('welcome' ); }); Route ::post ('/submit' , function () { }); Route ::put ('/update/{id}' , function ($id ) { }); Route ::delete ('/delete/{id}' , function ($id ) { });
Laravel 12 支持多种 HTTP 请求方法的路由,包括 GET、POST、PUT、DELETE 等,满足不同场景的需求。
Laravel 12 路由参数 我们可以在 Laravel 12 路由中定义参数,这些参数会传递给路由处理函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Route ::get ('/user/{id}' , function ($id ) { return 'User ' . $id ; }); Route ::get ('/user/{name?}' , function ($name = 'Guest' ) { return 'Hello ' . $name ; }); Route ::get ('/user/{id}' , function ($id ) { return 'User ' . $id ; })->where ('id' , '[0-9]+' );
Laravel 12 的路由参数系统非常灵活,支持必选参数、可选参数和带正则表达式约束的参数,满足各种复杂场景的需求。
Laravel 12 命名路由 我们可以为 Laravel 12 路由指定一个名称,这样在生成 URL 或重定向时可以使用这个名称,提高代码的可维护性:
1 2 3 4 5 6 7 8 9 10 Route ::get ('/user/{id}' , function ($id ) { return 'User ' . $id ; })->name ('user.show' ); $url = route ('user.show' , ['id' => 1 ]);return redirect ()->route ('user.show' , ['id' => 1 ]);
Laravel 12 的命名路由系统使得 URL 生成和重定向更加灵活和可维护,特别是在路由 URL 发生变化时,只需要修改路由定义,而不需要修改所有使用该路由的地方。
Laravel 12 路由组 Laravel 12 路由组允许我们为一组路由共享属性,如中间件、命名空间、前缀等,减少代码重复:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Route ::prefix ('admin' )->group (function () { Route ::get ('/users' , function () { return 'Admin Users' ; }); Route ::get ('/posts' , function () { return 'Admin Posts' ; }); }); Route ::namespace ('Admin' )->group (function () { Route ::get ('/admin/users' , 'UserController@index' ); }); Route ::middleware ('auth' )->group (function () { Route ::get ('/dashboard' , function () { return 'Dashboard' ; }); });
Laravel 12 的路由组系统非常强大,可以组合使用多种属性,如同时指定前缀、命名空间和中间件,使路由定义更加清晰和简洁。
3.2 Laravel 12 控制器 控制器是 Laravel 12 中处理 HTTP 请求的类,它们将请求逻辑组织成可维护的方法。Laravel 12 控制器位于 app/Http/Controllers 目录中,是 MVC 架构中的重要组成部分。
创建 Laravel 12 控制器 我们可以使用 Laravel 12 Artisan 命令生成控制器:
1 2 3 4 5 6 7 8 php artisan make:controller UserController php artisan make:controller PostController --resource php artisan make:controller CommentController --resource --model=Comment
Laravel 12 提供了多种控制器生成方式,满足不同场景的需求,提高开发效率。
Laravel 12 基本控制器 一个 Laravel 12 基本控制器如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 namespace App \Http \Controllers ;use Illuminate \Http \Request ;class UserController extends Controller { public function index ( ) { } public function show ($id ) { } public function create ( ) { } public function store (Request $request ) { } public function edit ($id ) { } public function update (Request $request , $id ) { } public function destroy ($id ) { } }
Laravel 12 基本控制器提供了一种组织请求处理逻辑的方式,将相关的方法集中在一个类中,提高代码的可维护性和可读性。
Laravel 12 资源控制器 Laravel 12 资源控制器是一种特殊的控制器,它为典型的 CRUD 操作提供了预设的方法,减少重复代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 namespace App \Http \Controllers ;use App \Models \Post ;use Illuminate \Http \Request ;class PostController extends Controller { public function index ( ) { $posts = Post ::all (); return view ('posts.index' , compact ('posts' )); } public function create ( ) { return view ('posts.create' ); } public function store (Request $request ) { $post = Post ::create ($request ->all ()); return redirect ()->route ('posts.show' , $post ->id); } public function show (Post $post ) { return view ('posts.show' , compact ('post' )); } public function edit (Post $post ) { return view ('posts.edit' , compact ('post' )); } public function update (Request $request , Post $post ) { $post ->update ($request ->all ()); return redirect ()->route ('posts.show' , $post ->id); } public function destroy (Post $post ) { $post ->delete (); return redirect ()->route ('posts.index' ); } }
Laravel 12 资源控制器自动为 CRUD 操作生成预设方法,包括 index、create、store、show、edit、update 和 destroy,大大减少了重复代码,提高了开发效率。
3.3 Laravel 12 路由与控制器结合 我们可以将 Laravel 12 路由指向控制器的方法,而不是使用闭包函数,这样可以更好地组织代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 use App \Http \Controllers \UserController ;Route ::get ('/users' , [UserController ::class , 'index' ]);Route ::get ('/users/{id}' , [UserController ::class , 'show' ]);Route ::resource ('posts' , 'PostController' );Route ::resource ('posts' , 'PostController' )->only ([ 'index' , 'show' ]); Route ::resource ('posts' , 'PostController' )->except ([ 'create' , 'store' , 'update' , 'destroy' ]); Route ::apiResource ('products' , 'ProductController' );
Laravel 12 的路由与控制器结合使用,使得代码结构更加清晰,职责更加分明,提高了代码的可维护性和可读性。
3.4 Laravel 12 路由模型绑定 Laravel 12 路由模型绑定允许我们自动将路由参数绑定到对应的模型实例,减少重复代码,提高开发效率:
Laravel 12 隐式路由模型绑定 1 2 3 4 5 6 7 8 9 Route ::get ('/posts/{post}' , [PostController ::class , 'show' ]);public function show (Post $post ) { return view ('posts.show' , compact ('post' )); }
Laravel 12 显式路由模型绑定 我们可以在 Laravel 12 的 RouteServiceProvider 中定义显式绑定:
1 2 3 4 5 6 7 8 9 10 11 12 public function boot ( ) { parent ::boot (); Route ::model ('user' , App\Models\User ::class ); } Route ::get ('/users/{user}' , function (App\Models\User $user ) { return $user ; });
Laravel 12 的路由模型绑定系统使得控制器代码更加简洁,减少了手动查找模型实例的代码,提高了代码的可读性和可维护性。
3.5 Laravel 12 中间件 Laravel 12 中间件是处理 HTTP 请求的过滤器,它们可以在请求到达控制器之前或之后执行操作,用于实现认证、日志记录、CSRF 保护等功能。
Laravel 12 应用中间件到路由 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Route ::get ('/dashboard' , function () { return view ('dashboard' ); })->middleware ('auth' ); Route ::middleware (['auth' , 'admin' ])->group (function () { Route ::get ('/admin/dashboard' , function () { return view ('admin.dashboard' ); }); }); class UserController extends Controller { public function __construct ( ) { $this ->middleware ('auth' ); $this ->middleware ('admin' )->only ('index' ); $this ->middleware ('guest' )->except ('index' ); } }
Laravel 12 中间件系统非常灵活,可以应用于单个路由、路由组或整个控制器,也可以通过 only 和 except 方法指定中间件应用于控制器的哪些方法。
3.6 Laravel 12 路由和控制器实战示例 现在,让我们创建一个简单的 Laravel 12 博客应用,来演示路由和控制器的使用:
创建 Laravel 12 控制器
1 php artisan make:controller PostController --resource
定义 Laravel 12 资源路由 在 routes/web.php 文件中:
1 2 3 use App \Http \Controllers \PostController ;Route ::resource ('posts' , PostController ::class );
实现 Laravel 12 控制器方法 在 app/Http/Controllers/PostController.php 文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 namespace App \Http \Controllers ;use Illuminate \Http \Request ;class PostController extends Controller { public function index ( ) { return view ('posts.index' ); } public function create ( ) { return view ('posts.create' ); } public function store (Request $request ) { return redirect ()->route ('posts.index' ); } public function show ($id ) { return view ('posts.show' , ['id' => $id ]); } public function edit ($id ) { return view ('posts.edit' , ['id' => $id ]); } public function update (Request $request , $id ) { return redirect ()->route ('posts.show' , $id ); } public function destroy ($id ) { return redirect ()->route ('posts.index' ); } }
创建 Laravel 12 视图文件 我们将在后面的章节中创建视图文件。
通过这个 Laravel 12 路由和控制器实战示例,你可以了解如何在实际项目中使用 Laravel 12 的路由和控制器,为后续的学习打下基础。
3.7 Laravel 12 路由缓存 对于 Laravel 12 生产环境,我们可以缓存路由以提高性能,减少路由解析时间:
1 2 3 4 5 php artisan route:cache php artisan route:clear
Laravel 12 路由缓存功能可以显著提高应用的性能,特别是在路由数量较多的情况下。但需要注意的是,每次修改路由后都需要重新生成路由缓存。
3.8 Laravel 12 路由列表 我们可以使用 Laravel 12 Artisan 命令查看应用的所有路由,了解路由的定义和映射关系:
Laravel 12 路由列表命令会显示应用中所有已定义的路由,包括路由方法、URI、名称、对应的控制器方法等信息,是开发过程中非常有用的工具。
现在,我们已经了解了 Laravel 12 的路由系统和控制器,接下来我们将学习 Laravel 12 的视图系统。
4. Laravel 12 视图 4.1 Laravel 12 视图基础 视图是 Laravel 12 应用的用户界面,Laravel 12 使用 Blade 模板引擎来渲染视图。Laravel 12 视图文件位于 resources/views 目录中,使用 .blade.php 扩展名。Blade 模板引擎提供了简洁的语法和强大的功能,是 Laravel 12 视图系统的核心。
Laravel 12 创建视图 我们可以在 Laravel 12 的 resources/views 目录中创建视图文件,使用 .blade.php 扩展名:
1 2 3 4 5 resources/views/welcome.blade.php resources/views/posts/index.blade.php
Laravel 12 支持嵌套目录结构来组织视图文件,这样可以更好地管理复杂应用的视图。
Laravel 12 渲染视图 在 Laravel 12 控制器中,我们可以使用 view 辅助函数来渲染视图,传递数据到视图:
1 2 3 4 5 6 7 8 9 10 11 12 return view ('welcome' );return view ('posts.index' );return view ('welcome' , ['name' => 'John' ]);$name = 'John' ;return view ('welcome' , compact ('name' ));
Laravel 12 提供了多种渲染视图的方式,包括基本渲染、嵌套目录视图渲染和数据传递,满足不同场景的需求。
4.2 Laravel 12 Blade 模板引擎 Blade 是 Laravel 12 提供的强大模板引擎,它提供了简洁的语法和丰富的功能,是 Laravel 12 视图系统的核心组件。Laravel 12 的 Blade 模板引擎支持模板继承、包含、条件语句、循环等多种功能,使视图开发更加高效和灵活。
Laravel 12 Blade 模板引擎基本语法 Laravel 12 Blade 模板引擎提供了简洁的语法和强大的功能,以下是常用的基本语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 {{-- Laravel 12 Blade 注释 --}} {{-- Laravel 12 输出变量(自动转义) --}} Hello, {{ $name }}! {{-- Laravel 12 输出变量(不转义) --}} {!! $html !!} {{-- Laravel 12 控制结构 --}} @if (count ($posts ) > 0 ) There are {{ count ($posts ) }} posts. @else There are no posts. @endif {{-- Laravel 12 循环 --}} @foreach ($posts as $post ) <p>{{ $post ->title }}</p> @endforeach @for ($i = 0 ; $i < 10 ; $i ++) <p>Item {{ $i }}</p> @endfor @while (true ) <p>Loop forever</p> @endwhile {{-- Laravel 12 包含子视图 --}} @include ('partials.header' ) {{-- Laravel 12 继承布局 --}} @extends ('layouts.app' ) @section ('content' ) <p>This is the content section</p> @endsection
Laravel 12 Blade 模板引擎的基本语法简洁明了,支持注释、变量输出、控制结构、循环、子视图包含和布局继承等功能,使视图开发更加高效和灵活。
Laravel 12 Blade 指令 Laravel 12 Blade 提供了许多有用的指令,简化视图开发:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 {{-- Laravel 12 条件指令 --}} @if (condition) @elseif (anotherCondition) @else @endif {{-- Laravel 12 身份验证指令 --}} @auth @endauth @guest @endguest {{-- Laravel 12 环境指令 --}} @env ('local' ) @endenv {{-- Laravel 12 推送到栈 --}} @push ('scripts' ) <script src="/js/script.js" ></script> @endpush {{-- Laravel 12 栈输出 --}} @stack ('scripts' ) {{-- Laravel 12 组件 --}} <x-alert type="error" :message="$message " /> {{-- Laravel 12 插槽 --}} <x-card> <x-slot name="header" > Card Header </x-slot> Card Content <x-slot name="footer" > Card Footer </x-slot> </x-card>
Laravel 12 Blade 指令提供了丰富的功能,包括条件判断、身份验证状态检查、环境检测、资源管理和组件系统等,使视图开发更加简洁和高效。
Laravel 12 自定义指令 Laravel 12 允许我们在 AppServiceProvider 中定义自定义 Blade 指令,扩展 Blade 模板引擎的功能:
1 2 3 4 5 6 7 8 9 10 11 public function boot ( ) { Blade ::directive ('datetime' , function ($expression ) { return "<?php echo ($expression )->format('m/d/Y H:i'); ?>" ; }); } @datetime ($date )
Laravel 12 自定义指令功能非常强大,可以根据项目需求创建各种自定义指令,简化视图代码,提高开发效率。
4.3 Laravel 12 布局 Laravel 12 布局允许我们创建一致的页面结构,减少代码重复,提高视图的可维护性。Laravel 12 布局使用 Blade 模板引擎的 @extends 和 @yield 指令来实现,是 Laravel 12 视图系统的重要组成部分。
Laravel 12 创建布局 我们可以在 Laravel 12 中创建布局文件,定义一致的页面结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 {{-- Laravel 12 布局文件: 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.0" > <title>@yield ('title' , 'Laravel 12 App' )</title> <link rel="stylesheet" href="{{ asset('css/app.css') }}" > @stack ('styles' ) </head> <body> <header> <nav> <!-- Laravel 12 导航菜单 --> </nav> </header> <main> @yield ('content' ) </main> <footer> <!-- Laravel 12 页脚内容 --> </footer> <script src="{{ asset('js/app.js') }}" ></script> @stack ('scripts' ) </body> </html>
Laravel 12 布局文件使用 @yield 指令定义内容区域,使用 @stack 指令定义可堆叠的资源区域,使页面结构更加清晰和可维护。
Laravel 12 使用布局 我们可以在 Laravel 12 视图中使用布局,继承一致的页面结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 {{-- Laravel 12 视图文件: resources/views/posts/index.blade.php --}} @extends ('layouts.app' ) @section ('title' , 'Posts' ) @push ('styles' ) <link rel="stylesheet" href="{{ asset('css/posts.css') }}" > @endpush @section ('content' ) <h1>Posts</h1> @foreach ($posts as $post ) <div class ="post "> <h2 > {{ $post ->title }}</h2> <p>{{ $post ->content }}</p> </div> @endforeach @endsection @push ('scripts' ) <script src="{{ asset('js/posts.js') }}" ></script> @endpush
Laravel 12 使用布局的方式非常简单,通过 @extends 指令继承布局文件,通过 @section 指令填充内容区域,通过 @push 指令添加页面特定的资源,使视图开发更加模块化和可维护。
4.4 Laravel 12 组件 Laravel 12 组件是可重用的视图片段,可以接受属性和插槽,使视图开发更加模块化和可维护。Laravel 12 组件系统非常强大,支持类组件和匿名组件,是 Laravel 12 视图系统的重要组成部分。
Laravel 12 创建组件 我们可以使用 Laravel 12 Artisan 命令生成组件,创建可重用的视图片段:
1 2 3 4 5 php artisan make:component Alert php artisan make:component Forms/Input
Laravel 12 提供了便捷的 Artisan 命令来生成组件,支持基本组件和嵌套组件,使组件开发更加高效和规范化。
Laravel 12 组件结构 Laravel 12 组件由组件类和组件视图两部分组成,以下是组件视图的结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 {{-- Laravel 12 组件视图: resources/views/components/alert.blade.php --}} <div class ="alert alert - {{ $type }}"> {{ $message }} </div> {{-- Laravel 12 带插槽的组件 --}} <div class=" card"> @if (isset($header )) <div class=" card-header"> {{ $header }} </div> @endif <div class=" card-body"> {{ $slot }} </div> @if (isset($footer )) <div class=" card-footer"> {{ $footer }} </div> @endif </div>
Laravel 12 组件结构支持传递属性和插槽,使组件更加灵活和可重用。组件视图使用 Blade 模板语法,可以包含 HTML、PHP 代码和 Blade 指令。
Laravel 12 使用组件 我们可以在 Laravel 12 视图中使用组件,实现视图片段的重用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 {{-- Laravel 12 组件基本使用 --}} <x-alert type="success" message="Operation completed successfully!" /> {{-- Laravel 12 组件使用插槽 --}} <x-card> <x-slot name="header" > <h3>Card Title</h3> </x-slot> <p>This is the card content.</p> <x-slot name="footer" > <button class ="btn btn -primary ">Submit </button > </x -slot > </x -card >
Laravel 12 使用组件的方式非常简单,通过 <x-组件名> 标签来使用组件,支持传递属性和使用插槽,使视图开发更加模块化和可维护。组件是 Laravel 12 视图系统的重要组成部分,可以大大提高开发效率和代码质量。
Laravel 12 组件类 我们可以为 Laravel 12 组件创建对应的类,用于处理逻辑和数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 namespace App \View \Components ;use Illuminate \View \Component ;class Alert extends Component { public $type ; public $message ; public function __construct ($type = 'info' , $message = '' ) { $this ->type = $type ; $this ->message = $message ; } public function render ( ) { return view ('components.alert' ); } }
Laravel 12 组件类负责处理组件的逻辑和数据,通过构造函数接受属性,通过 render 方法返回组件视图,使组件开发更加模块化和可维护。组件类是 Laravel 12 组件系统的重要组成部分,为组件提供了强大的逻辑处理能力。
4.5 Laravel 12 视图助手函数 Laravel 12 提供了许多有用的视图助手函数,简化视图开发,提高开发效率:
Laravel 12 URL 助手 Laravel 12 提供了丰富的 URL 助手函数,用于生成各种类型的 URL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 {{-- Laravel 12 生成应用 URL --}} {{ url ('/' ) }} {{-- Laravel 12 生成安全 URL --}} {{ secure_url ('/' ) }} {{-- Laravel 12 生成资源 URL --}} {{ asset ('css/app.css' ) }} {{-- Laravel 12 生成路由 URL --}} {{ route ('posts.show' , ['id' => 1 ]) }} {{-- Laravel 12 生成控制器动作 URL --}} {{ action ([PostController ::class , 'show' ], ['id' => 1 ]) }}
Laravel 12 URL 助手函数非常强大,支持生成应用 URL、安全 URL、资源 URL、路由 URL 和控制器动作 URL 等多种类型的 URL,满足不同场景的需求。
Laravel 12 表单助手 Laravel 12 提供了表单助手函数,用于生成表单相关的 HTML 元素:
1 2 3 4 5 {{-- Laravel 12 CSRF 令牌 --}} {{ csrf_field () }} {{-- Laravel 12 方法字段 --}} {{ method_field ('PUT' ) }}
Laravel 12 表单助手函数简化了表单开发,特别是 CSRF 保护和 HTTP 方法伪造等功能,提高了表单的安全性和可靠性。
Laravel 12 认证助手 Laravel 12 提供了认证助手函数,用于检查用户认证状态和获取用户信息:
1 2 3 4 5 {{-- Laravel 12 检查用户是否已认证 --}} {{ auth ()->check () }} {{-- Laravel 12 获取当前用户 --}} {{ auth ()->user () }}
Laravel 12 认证助手函数简化了用户认证相关的操作,使视图中可以方便地检查用户状态和获取用户信息,提高了视图开发的效率和可读性。
4.6 Laravel 12 视图实战示例 现在,让我们为之前创建的 Laravel 12 博客应用创建视图文件,演示 Laravel 12 视图系统的实际使用:
创建 Laravel 12 布局文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 {{-- Laravel 12 布局文件: 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.0" > <title>@yield ('title' , 'Laravel 12 Blog' )</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" > </head> <body> <nav class ="navbar navbar -expand -lg navbar -light bg -light "> <div class ="container "> <a class ="navbar -brand " href =" {{ route ('posts.index' ) }}">Laravel 12 Blog</a> <div class=" collapse navbar-collapse"> <ul class=" navbar-nav mr-auto"> <li class=" nav-item"> <a class=" nav-link" href=" {{ route ('posts.index' ) }}">Home</a> </li> <li class=" nav-item"> <a class=" nav-link" href=" {{ route ('posts.create' ) }}">Create Post</a> </li> </ul> </div> </div> </nav> <div class=" container mt-4 "> @yield('content') </div> <script src=" https:</body> </html>
创建 Laravel 12 帖子列表视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{-- Laravel 12 帖子列表视图: resources/views/posts/index.blade.php --}} @extends ('layouts.app' ) @section ('title' , 'Posts' ) @section ('content' ) <h1>Posts</h1> <div class ="mb -4"> <a href =" {{ route ('posts.create' ) }}" class=" btn btn-primary">Create Post</a> </div> <div class=" list -group"> <!-- Laravel 12 暂时使用模拟数据 --> <a href=" {{ route ('posts.show' , ['id' => 1 ]) }}" class=" list -group-item list -group-item-action"> <h5 class=" mb-1 ">Post 1</h5> <p class=" mb-1 ">This is the first post.</p> </a> <a href=" {{ route ('posts.show' , ['id' => 2 ]) }}" class=" list -group-item list -group-item-action"> <h5 class=" mb-1 ">Post 2</h5> <p class=" mb-1 ">This is the second post.</p> </a> </div> @endsection
创建 Laravel 12 帖子创建视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{-- Laravel 12 帖子创建视图: resources/views/posts/create.blade.php --}} @extends ('layouts.app' ) @section ('title' , 'Create Post' ) @section ('content' ) <h1>Create Post</h1> <form action="{{ route('posts.store') }}" method="POST" > @csrf <div class ="mb -3"> <label for ="title " class ="form -label ">Title </label > <input type ="text " class ="form -control " id ="title " name ="title " required > </div > <div class ="mb -3"> <label for ="content " class ="form -label ">Content </label > <textarea class ="form -control " id ="content " name ="content " rows ="3" required ></textarea > </div > <button type ="submit " class ="btn btn -primary ">Submit </button > </form > @endsection
创建 Laravel 12 帖子显示视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 {{-- Laravel 12 帖子显示视图: resources/views/posts/show.blade.php --}} @extends ('layouts.app' ) @section ('title' , 'Post' ) @section ('content' ) <h1>Post {{ $id }}</h1> <div class ="card "> <div class ="card -body "> <h5 class ="card -title ">Post {{ $id }}</h5> <p class ="card -text ">This is post {{ $id }} content.</p> <a href="{{ route('posts.edit', ['id' => $id ]) }}" class ="btn btn -primary ">Edit </a > <form action =" {{ route ('posts.destroy' , ['id' => $id ]) }}" method=" POST" style=" display: inline;"> @csrf @method('DELETE') <button type=" submit" class=" btn btn-danger">Delete</button> </form> <a href=" {{ route ('posts.index' ) }}" class=" btn btn-secondary">Back</a> </div> </div> @endsection
创建 Laravel 12 帖子编辑视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 {{-- Laravel 12 帖子编辑视图: resources/views/posts/edit.blade.php --}} @extends ('layouts.app' ) @section ('title' , 'Edit Post' ) @section ('content' ) <h1>Edit Post {{ $id }}</h1> <form action="{{ route('posts.update', ['id' => $id ]) }}" method="POST" > @csrf @method ('PUT' ) <div class ="mb -3"> <label for ="title " class ="form -label ">Title </label > <input type ="text " class ="form -control " id ="title " name ="title " value ="Post {{ $id }}" required> </div> <div class=" mb-3 "> <label for=" content" class=" form-label">Content</label> <textarea class=" form-control" id=" content" name=" content" rows=" 3 " required>This is post {{ $id }} content.</textarea> </div> <button type=" submit" class=" btn btn-primary">Update</button> <a href=" {{ route ('posts.show' , ['id' => $id ]) }}" class=" btn btn-secondary">Cancel</a> </form> @endsection
4.7 Laravel 12 视图缓存 对于 Laravel 12 生产环境,Laravel 12 会自动缓存编译后的 Blade 模板,以提高性能。视图缓存可以显著减少模板编译时间,提升应用响应速度:
1 2 3 4 5 php artisan view:clear php artisan view:cache
Laravel 12 视图缓存机制非常智能,当模板文件发生变化时,会自动重新编译,确保视图始终是最新的。在生产环境中使用视图缓存可以显著提升 Laravel 12 应用的性能,减少服务器负载,提高用户体验。
现在,我们已经了解了 Laravel 12 的视图系统,接下来我们将学习 Laravel 12 的数据库操作。
5. Laravel 12 数据库操作 Laravel 12 提供了多种数据库操作方式,包括数据库迁移、Eloquent ORM、查询构建器和原始 SQL 查询。Laravel 12 的数据库操作非常强大和灵活,支持多种数据库系统,如 MySQL、PostgreSQL、SQLite 和 SQL Server 等。
5.1 Laravel 12 数据库配置 Laravel 12 的数据库配置位于 config/database.php 文件中,我们可以在 .env 文件中设置数据库连接信息。Laravel 12 支持多种数据库系统,包括 MySQL、PostgreSQL、SQLite 和 SQL Server 等,配置简单直观。
Laravel 12 配置数据库连接 Laravel 12 支持多种数据库系统,我们可以在 .env 文件中配置数据库连接信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # Laravel 12 MySQL 配置 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD= # Laravel 12 PostgreSQL 配置 # DB_CONNECTION=pgsql # DB_HOST=127.0.0.1 # DB_PORT=5432 # DB_DATABASE=laravel # DB_USERNAME=root # DB_PASSWORD= # Laravel 12 SQLite 配置 # DB_CONNECTION=sqlite # DB_DATABASE=/path/to/database.sqlite
Laravel 12 的数据库配置非常灵活,我们可以根据项目需求选择不同的数据库系统,并在 .env 文件中设置相应的连接信息。
5.2 Laravel 12 数据库迁移 Laravel 12 数据库迁移是一种版本控制数据库结构的方法,允许我们定义和修改数据库表结构。Laravel 12 数据库迁移使用 PHP 代码来定义数据库结构,而不是 SQL 语句,使数据库结构管理更加灵活和可维护。
Laravel 12 创建迁移 我们可以使用 Laravel 12 Artisan 命令生成迁移,创建数据库表结构:
1 2 3 4 5 6 7 8 php artisan make:migration create_users_table php artisan make:migration create_users_table --create=users php artisan make:migration add_email_to_users_table --table=users
Laravel 12 提供了便捷的 Artisan 命令来生成迁移文件,支持创建新表和修改现有表的迁移,使数据库结构管理更加高效和规范化。
Laravel 12 迁移结构 Laravel 12 迁移文件由一个包含 up() 和 down() 方法的类组成,结构清晰,易于维护:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 use Illuminate \Database \Migrations \Migration ;use Illuminate \Database \Schema \Blueprint ;use Illuminate \Support \Facades \Schema ;class CreateUsersTable extends Migration { public function up ( ) { Schema ::create ('users' , function (Blueprint $table ) { $table ->id (); $table ->string ('name' ); $table ->string ('email' )->unique (); $table ->timestamp ('email_verified_at' )->nullable (); $table ->string ('password' ); $table ->rememberToken (); $table ->timestamps (); }); } public function down ( ) { Schema ::dropIfExists ('users' ); } }
Laravel 12 迁移结构设计合理,up() 方法用于创建或修改数据库表结构,down() 方法用于回滚这些更改,使数据库结构管理更加灵活和可维护。
Laravel 12 运行迁移 我们可以使用 Laravel 12 Artisan 命令运行和管理迁移,执行数据库结构变更:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 php artisan migrate php artisan migrate:rollback php artisan migrate:reset php artisan migrate:fresh php artisan migrate:fresh --seed
Laravel 12 提供了完整的迁移管理命令,支持运行、回滚、重置和刷新迁移等操作,使数据库结构管理更加灵活和可控。
Laravel 12 迁移列类型 Laravel 12 提供了多种列类型,用于定义数据库表字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $table ->id (); $table ->string ('name' ); $table ->text ('description' ); $table ->integer ('age' ); $table ->bigInteger ('price' ); $table ->float ('rate' ); $table ->double ('score' ); $table ->decimal ('amount' , 8 , 2 ); $table ->boolean ('active' ); $table ->date ('birthday' ); $table ->time ('time' ); $table ->datetime ('created_at' ); $table ->timestamp ('updated_at' ); $table ->json ('data' ); $table ->enum ('status ', ['active ', 'inactive ']); // Laravel 12 枚举$table ->foreignId ('user_id '); // Laravel 12 外键
Laravel 12 提供了丰富的列类型,满足不同场景的数据库字段需求,使数据库结构定义更加灵活和精确。
Laravel 12 列修饰符 Laravel 12 提供了多种列修饰符,用于定义数据库字段的属性:
1 2 3 4 5 6 7 $table ->string ('name' )->nullable (); $table ->string ('email' )->unique (); $table ->string ('password' )->default ('secret' ); $table ->integer ('age' )->unsigned (); $table ->string ('name' )->length (100 ); $table ->integer ('order' )->autoIncrement (); $table ->string ('name' )->comment ('用户名称' );
Laravel 12 列修饰符非常强大,可以定义字段的各种属性,如可为空、唯一、默认值、长度、自增和注释等,使数据库字段定义更加精确和灵活。
Laravel 12 索引 Laravel 12 提供了多种索引类型,用于优化数据库查询性能:
1 2 3 4 5 6 7 $table ->index ('email' ); $table ->unique ('email' ); $table ->primary ('id' ); $table ->foreign ('user_id' )->references ('id' )->on ('users' ); $table ->index (['first_name' , 'last_name' ]);
Laravel 12 索引非常强大,可以定义普通索引、唯一索引、主键和外键等多种类型的索引,以及复合索引,大大提高数据库查询性能。
5.3 Laravel 12 数据库填充 Laravel 12 数据库填充用于向数据库中添加初始数据,如默认用户、配置数据等。Laravel 12 数据库填充使用填充器和模型工厂来生成和插入数据,使数据填充更加高效和灵活。
Laravel 12 创建填充器 我们可以使用 Laravel 12 Artisan 命令创建填充器和模型工厂,用于生成和插入初始数据:
1 2 3 4 5 php artisan make:seeder UserSeeder php artisan make:factory UserFactory
Laravel 12 提供了便捷的 Artisan 命令来创建填充器和模型工厂,使数据填充更加高效和规范化。
Laravel 12 填充器结构 Laravel 12 填充器由一个包含 run() 方法的类组成,用于向数据库中插入初始数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 use Illuminate \Database \Seeder ;use Illuminate \Support \Facades \DB ;class UserSeeder extends Seeder { public function run ( ) { DB::table ('users' )->insert ([ 'name' => 'Admin' , 'email' => 'admin@example.com' , 'password' => bcrypt ('password' ), ]); } }
Laravel 12 填充器结构设计合理,通过 run() 方法执行数据填充操作,可以使用 DB 门面或模型工厂来插入数据,使数据填充更加灵活和可控。
Laravel 12 模型工厂 Laravel 12 模型工厂用于生成模型的测试数据,支持使用 Faker 库生成各种类型的假数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 use App \Models \User ;use Illuminate \Database \Eloquent \Factories \Factory ;use Illuminate \Support \Str ;class UserFactory extends Factory { protected $model = User ::class ; public function definition ( ) { return [ 'name' => $this ->faker->name, 'email' => $this ->faker->unique ()->safeEmail, 'email_verified_at' => now (), 'password' => bcrypt ('password' ), 'remember_token' => Str ::random (10 ), ]; } }
Laravel 12 模型工厂非常强大,支持生成各种类型的假数据,如姓名、邮箱、地址等,使数据填充更加高效和灵活。
Laravel 12 使用模型工厂 我们可以在 Laravel 12 填充器中使用模型工厂来生成和插入大量测试数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 use App \Models \User ;use Illuminate \Database \Seeder ;class DatabaseSeeder extends Seeder { public function run ( ) { User ::factory ()->count (10 )->create (); User ::factory ()->count (5 )->create ([ 'role' => 'admin' , ]); } }
Laravel 12 模型工厂非常强大,可以快速生成大量测试数据,也可以指定特定属性,使数据填充更加灵活和可控。
Laravel 12 运行填充器 我们可以使用 Laravel 12 Artisan 命令运行填充器,向数据库中插入初始数据:
1 2 3 4 5 6 7 8 php artisan db:seed --class=UserSeeder php artisan db:seed php artisan migrate:fresh --seed
Laravel 12 提供了完整的填充器管理命令,支持运行指定填充器、运行所有填充器,以及重新迁移并运行填充器等操作,使数据填充更加灵活和可控。
5.4 Laravel 12 Eloquent ORM Eloquent 是 Laravel 12 提供的 ORM(对象关系映射),允许我们使用 PHP 对象来操作数据库。Laravel 12 Eloquent ORM 非常强大,支持模型关联、查询作用域、访问器和修改器等多种功能,使数据库操作更加简洁和优雅。
Laravel 12 创建模型 我们可以使用 Laravel 12 Artisan 命令创建模型,定义数据库表结构的 PHP 表示:
1 2 3 4 5 6 7 8 php artisan make:model User php artisan make:model User -m php artisan make:model User -mcr
Laravel 12 提供了便捷的 Artisan 命令来创建模型,支持创建带迁移和控制器的模型,使模型开发更加高效和规范化。
Laravel 12 模型结构 Laravel 12 模型由一个继承自 Model 类的 PHP 类组成,结构清晰,易于维护:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 namespace App \Models ;use Illuminate \Database \Eloquent \Factories \HasFactory ;use Illuminate \Database \Eloquent \Model ;class User extends Model { use HasFactory ; protected $fillable = [ 'name' , 'email' , 'password' , ]; protected $hidden = [ 'password' , 'remember_token' , ]; protected $casts = [ 'email_verified_at' => 'datetime' , ]; }
Laravel 12 模型结构设计合理,支持定义可批量赋值的属性、隐藏的属性和类型转换等,使模型操作更加安全和灵活。
Laravel 12 基本查询 Laravel 12 Eloquent ORM 提供了丰富的查询方法,用于从数据库中检索数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 use App \Models \User ;$users = User ::all ();$user = User ::find (1 );$user = User ::where ('email' , 'admin@example.com' )->first ();$users = User ::where ('age' , '>' , 18 )->get ();$users = User ::orderBy ('name' , 'asc' )->get ();$users = User ::paginate (10 );$count = User ::count ();$max = User ::max ('age' );$min = User ::min ('age' );$avg = User ::avg ('age' );$sum = User ::sum ('score' );
Laravel 12 基本查询非常强大,支持获取所有记录、根据 ID 获取记录、根据条件获取记录、排序、分页和聚合函数等多种操作,使数据库查询更加简洁和优雅。
Laravel 12 创建记录 Laravel 12 Eloquent ORM 提供了多种方法来创建数据库记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 $user = User ::create ([ 'name' => 'John Doe' , 'email' => 'john@example.com' , 'password' => bcrypt ('password' ), ]); $user = new User ;$user ->name = 'John Doe' ;$user ->email = 'john@example.com' ;$user ->password = bcrypt ('password' );$user ->save ();
Laravel 12 创建记录非常简单,支持使用 create 方法和 save 方法来创建数据库记录,使数据插入操作更加简洁和优雅。
Laravel 12 更新记录 Laravel 12 Eloquent ORM 提供了多种方法来更新数据库记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 $user = User ::find (1 );$user ->update ([ 'name' => 'Jane Doe' , ]); $user = User ::find (1 );$user ->name = 'Jane Doe' ;$user ->save ();User ::where ('active' , 1 )->update (['status' => 'verified' ]);
Laravel 12 更新记录非常灵活,支持使用 update 方法、save 方法和批量更新来修改数据库记录,使数据更新操作更加简洁和优雅。
Laravel 12 删除记录 Laravel 12 Eloquent ORM 提供了多种方法来删除数据库记录:
1 2 3 4 5 6 7 8 9 10 $user = User ::find (1 );$user ->delete ();User ::destroy (1 );User ::destroy ([1 , 2 , 3 ]);User ::where ('active' , 0 )->delete ();
Laravel 12 删除记录非常灵活,支持使用 delete 方法、destroy 方法和批量删除来移除数据库记录,使数据删除操作更加简洁和优雅。
Laravel 12 软删除 Laravel 12 Eloquent ORM 支持软删除,允许我们标记记录为已删除而不是真正从数据库中删除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 use Illuminate \Database \Eloquent \SoftDeletes ;class User extends Model { use HasFactory , SoftDeletes ; } $table ->softDeletes ();$user = User ::find (1 );$user ->delete ();$users = User ::withTrashed ()->get ();$users = User ::onlyTrashed ()->get ();$user = User ::withTrashed ()->find (1 );$user ->restore ();$user = User ::withTrashed ()->find (1 );$user ->forceDelete ();
Laravel 12 软删除非常强大,支持标记记录为已删除、恢复软删除的记录、强制删除记录和查询软删除的记录等操作,使数据删除操作更加灵活和安全。
5.5 Laravel 12 关联关系 Laravel 12 Eloquent ORM 支持多种关联关系:一对一、一对多、多对多、多态关联等。Laravel 12 关联关系非常强大,允许我们轻松定义和查询模型之间的关系,使数据库操作更加简洁和优雅。
Laravel 12 一对一关联 Laravel 12 Eloquent ORM 支持一对一关联,允许我们定义两个模型之间的一对一关系:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public function profile ( ) { return $this ->hasOne (Profile ::class ); } public function user ( ) { return $this ->belongsTo (User ::class ); } $user = User ::find (1 );$profile = $user ->profile;$profile = Profile ::find (1 );$user = $profile ->user;
Laravel 12 一对一关联非常强大,支持定义关联关系、使用关联和反向使用关联等操作,使模型之间的关系管理更加简洁和优雅。
Laravel 12 一对多关联 Laravel 12 Eloquent ORM 支持一对多关联,允许我们定义一个模型与多个其他模型之间的关系:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public function comments ( ) { return $this ->hasMany (Comment ::class ); } public function post ( ) { return $this ->belongsTo (Post ::class ); } $post = Post ::find (1 );$comments = $post ->comments;$comment = Comment ::find (1 );$post = $comment ->post;
Laravel 12 一对多关联非常强大,支持定义关联关系、使用关联和反向使用关联等操作,使模型之间的关系管理更加简洁和优雅。
Laravel 12 多对多关联 Laravel 12 Eloquent ORM 支持多对多关联,允许我们定义两个模型之间的多对多关系:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public function roles ( ) { return $this ->belongsToMany (Role ::class ); } public function users ( ) { return $this ->belongsToMany (User ::class ); } $user = User ::find (1 );$roles = $user ->roles;$role = Role ::find (1 );$users = $role ->users;$user ->roles ()->attach ($roleId );$user ->roles ()->detach ($roleId );$user ->roles ()->sync ([1 , 2 , 3 ]);
Laravel 12 多对多关联非常强大,支持定义关联关系、使用关联、附加关联、分离关联和同步关联等操作,使模型之间的关系管理更加简洁和优雅。
Laravel 12 关联查询 Laravel 12 Eloquent ORM 提供了多种方法来查询关联数据,优化数据库查询性能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $users = User ::with ('profile' )->get ();$posts = Post ::with ('comments.user' )->get ();$users = User ::all ();$users ->load ('profile' );$users = User ::with (['profile' => function ($query ) { $query ->where ('active' , 1 ); }])->get ();
Laravel 12 关联查询非常强大,支持预加载关联、嵌套预加载、延迟预加载和条件预加载等操作,大大提高了数据库查询性能,避免了 N+1 查询问题。
5.6 Laravel 12 查询构建器 Laravel 12 查询构建器提供了一种流畅的接口来构建 SQL 查询,支持各种数据库操作。Laravel 12 查询构建器非常强大,允许我们使用链式方法来构建复杂的 SQL 查询,而不需要直接编写 SQL 语句。
Laravel 12 基本查询 Laravel 12 查询构建器提供了丰富的方法来构建和执行 SQL 查询:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 use Illuminate \Support \Facades \DB ;$users = DB::table ('users' )->get ();$users = DB::table ('users' )->where ('age' , '>' , 18 )->get ();$users = DB::table ('users' )->orderBy ('name' , 'asc' )->get ();$users = DB::table ('users' )->limit (10 )->offset (5 )->get ();$count = DB::table ('users' )->count ();$max = DB::table ('users' )->max ('age' );
Laravel 12 基本查询非常强大,支持选择、条件、排序、限制和聚合等操作,使数据库查询更加简洁和优雅。
Laravel 12 连接 Laravel 12 查询构建器支持多种类型的数据库连接,用于关联多个表的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 $users = DB::table ('users' ) ->join ('profiles' , 'users.id' , '=' , 'profiles.user_id' ) ->select ('users.*' , 'profiles.bio' ) ->get (); $users = DB::table ('users' ) ->leftJoin ('profiles' , 'users.id' , '=' , 'profiles.user_id' ) ->select ('users.*' , 'profiles.bio' ) ->get (); $users = DB::table ('users' ) ->rightJoin ('profiles' , 'users.id' , '=' , 'profiles.user_id' ) ->select ('users.*' , 'profiles.bio' ) ->get (); $users = DB::table ('users' ) ->crossJoin ('roles' ) ->get ();
Laravel 12 连接非常强大,支持内连接、左连接、右连接和交叉连接等多种类型的连接操作,使多表查询更加简洁和优雅。
Laravel 12 高级条件 Laravel 12 查询构建器支持多种高级条件查询,允许我们构建复杂的查询条件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 $users = DB::table ('users' )->where ('age' , '>' , 18 )->get ();$users = DB::table ('users' ) ->where ('age' , '>' , 18 ) ->where ('active' , 1 ) ->get (); $users = DB::table ('users' ) ->where ('age' , '>' , 18 ) ->orWhere ('active' , 1 ) ->get (); $users = DB::table ('users' ) ->where (function ($query ) { $query ->where ('age' , '>' , 18 ) ->orWhere ('active' , 1 ); }) ->where ('verified' , 1 ) ->get (); $users = DB::table ('users' ) ->whereBetween ('age' , [18 , 30 ]) ->get (); $users = DB::table ('users' ) ->whereIn ('id' , [1 , 2 , 3 ]) ->get (); $users = DB::table ('users' ) ->whereNull ('email_verified_at' ) ->get ();
Laravel 12 高级条件非常强大,支持基本条件、多个条件、或条件、分组条件、范围条件、列表条件和空值条件等多种查询方式,使复杂查询的构建更加简洁和优雅。
Laravel 12 插入、更新和删除 Laravel 12 查询构建器支持插入、更新和删除操作,用于修改数据库中的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 DB::table ('users' )->insert ([ 'name' => 'John Doe' , 'email' => 'john@example.com' , ]); $id = DB::table ('users' )->insertGetId ([ 'name' => 'John Doe' , 'email' => 'john@example.com' , ]); DB::table ('users' )->insert ([ ['name' => 'John Doe' , 'email' => 'john@example.com' ], ['name' => 'Jane Doe' , 'email' => 'jane@example.com' ], ]); DB::table ('users' )->where ('id' , 1 )->update ([ 'name' => 'Jane Doe' , ]); DB::table ('users' )->where ('id' , 1 )->increment ('age' ); DB::table ('users' )->where ('id' , 1 )->decrement ('age' ); DB::table ('users' )->where ('id' , 1 )->delete (); DB::table ('users' )->truncate ();
Laravel 12 插入、更新和删除操作非常强大,支持插入单条记录、插入并返回 ID、批量插入、更新记录、自增、自减、删除记录和截断表等操作,使数据修改更加简洁和优雅。
5.7 Laravel 12 原始 SQL 查询 在某些情况下,我们可能需要使用原始 SQL 查询。Laravel 12 支持执行原始 SQL 查询,允许我们直接编写和执行 SQL 语句,为复杂查询提供更大的灵活性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $users = DB::select ('SELECT * FROM users WHERE active = ?' , [1 ]);DB::insert ('INSERT INTO users (name, email) VALUES (?, ?)' , ['John Doe' , 'john@example.com' ]); DB::update ('UPDATE users SET active = ? WHERE id = ?' , [1 , 1 ]); DB::delete ('DELETE FROM users WHERE id = ?' , [1 ]); DB::statement ('DROP TABLE IF EXISTS users' ); DB::transaction (function () { DB::update ('UPDATE users SET votes = votes + 1 WHERE id = ?' , [1 ]); DB::delete ('DELETE FROM posts WHERE user_id = ?' , [1 ]); });
5.8 Laravel 12 事务 Laravel 12 事务用于确保一系列数据库操作要么全部成功,要么全部失败,保证数据的一致性和完整性。
Laravel 12 自动事务 1 2 3 4 5 6 7 use Illuminate \Support \Facades \DB ;DB::transaction (function () { DB::table ('users' )->update (['votes' => 1 ]); DB::table ('posts' )->delete (); });
Laravel 12 手动事务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 use Illuminate \Support \Facades \DB ;DB::beginTransaction (); try { DB::table ('users' )->update (['votes' => 1 ]); DB::table ('posts' )->delete (); DB::commit (); } catch (\Exception $e ) { DB::rollBack (); }
Laravel 12 事务嵌套 1 2 3 4 5 6 7 8 9 DB::transaction (function () { DB::table ('users' )->update (['votes' => 1 ]); DB::transaction (function () { DB::table ('posts' )->delete (); }, 5 ); }, 3 );
Laravel 12 事务非常强大,支持自动事务、手动事务和事务嵌套等多种方式,并提供了事务重试机制,使数据库操作更加安全和可靠。
5.9 Laravel 12 实战示例 现在,让我们为之前创建的 Laravel 12 博客应用添加数据库功能:
创建帖子迁移
1 php artisan make:migration create_posts_table
编辑迁移文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 use Illuminate \Database \Migrations \Migration ;use Illuminate \Database \Schema \Blueprint ;use Illuminate \Support \Facades \Schema ;class CreatePostsTable extends Migration { public function up ( ) { Schema ::create ('posts' , function (Blueprint $table ) { $table ->id (); $table ->string ('title' ); $table ->text ('content' ); $table ->timestamps (); }); } public function down ( ) { Schema ::dropIfExists ('posts' ); } }
运行迁移
创建帖子模型
1 php artisan make:model Post
编辑模型文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 namespace App \Models ;use Illuminate \Database \Eloquent \Factories \HasFactory ;use Illuminate \Database \Eloquent \Model ;class Post extends Model { use HasFactory ; protected $fillable = [ 'title' , 'content' , ]; }
更新控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 namespace App \Http \Controllers ;use App \Models \Post ;use Illuminate \Http \Request ;class PostController extends Controller { public function index ( ) { $posts = Post ::all (); return view ('posts.index' , compact ('posts' )); } public function create ( ) { return view ('posts.create' ); } public function store (Request $request ) { Post ::create ($request ->all ()); return redirect ()->route ('posts.index' ); } public function show (Post $post ) { return view ('posts.show' , compact ('post' )); } public function edit (Post $post ) { return view ('posts.edit' , compact ('post' )); } public function update (Request $request , Post $post ) { $post ->update ($request ->all ()); return redirect ()->route ('posts.show' , $post ); } public function destroy (Post $post ) { $post ->delete (); return redirect ()->route ('posts.index' ); } }
更新路由
1 2 3 use App \Http \Controllers \PostController ;Route ::resource ('posts' , PostController ::class );
更新视图
更新 posts/index.blade.php 以显示实际数据 更新 posts/show.blade.php 以显示实际数据 更新 posts/edit.blade.php 以显示实际数据 创建帖子填充器
1 php artisan make:seeder PostSeeder
编辑填充器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 use Illuminate \Database \Seeder ;use App \Models \Post ;class PostSeeder extends Seeder { public function run ( ) { Post ::create ([ 'title' => 'First Post' , 'content' => 'This is the first post content.' , ]); Post ::create ([ 'title' => 'Second Post' , 'content' => 'This is the second post content.' , ]); } }
运行填充器
1 php artisan db:seed --class=PostSeeder
现在,我们的博客应用已经具备了完整的数据库功能,可以创建、查看、编辑和删除帖子。
5.10 Laravel 12 数据库优化 Laravel 12 提供了多种数据库优化技术,帮助我们提高应用的性能和可靠性。
Laravel 12 索引优化 为经常查询的列添加索引 为外键添加索引 避免过多的索引(会影响插入和更新性能) 使用复合索引优化多列查询 在 Laravel 12 迁移中使用 $table->index() 方法添加索引 Laravel 12 查询优化 使用预加载减少 N+1 查询问题:Post::with('comments')->get(); 只选择需要的列:User::select('id', 'name')->get(); 使用分页避免一次性获取过多数据:Post::paginate(10); 避免在循环中执行数据库操作 使用缓存减少数据库查询:Cache::remember('users', 60, function () { return User::all(); }); Laravel 12 连接池优化 在生产环境中配置合适的数据库连接池大小 关闭不需要的连接 使用连接池监控工具 在 Laravel 12 中通过 config/database.php 配置连接池参数 通过这些 Laravel 12 数据库优化技术,你可以显著提高应用的性能和响应速度,为用户提供更好的体验。
现在,我们已经了解了 Laravel 的数据库操作,接下来我们将学习 Laravel 的表单处理。
6. Laravel 12 表单处理 Laravel 12 表单处理是 Web 应用中的常见任务,Laravel 12 提供了强大的表单处理功能,包括表单验证、CSRF 保护等。
6.1 Laravel 12 基本表单处理 Laravel 12 创建表单 在 Laravel 12 中,我们可以使用 HTML 表单或 Laravel 12 提供的表单助手来创建表单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <form action ="{{ route('posts.store') }}" method ="POST" > @csrf <div class ="mb-3" > <label for ="title" class ="form-label" > Title</label > <input type ="text" class ="form-control" id ="title" name ="title" required > </div > <div class ="mb-3" > <label for ="content" class ="form-label" > Content</label > <textarea class ="form-control" id ="content" name ="content" rows ="3" required > </textarea > </div > <button type ="submit" class ="btn btn-primary" > Submit</button > </form >
Laravel 12 处理表单提交 在 Laravel 12 控制器中,我们可以使用 Request 对象来获取表单数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 use Illuminate \Http \Request ;public function store (Request $request ) { $title = $request ->input ('title' ); $content = $request ->input ('content' ); $data = $request ->all (); $data = $request ->only (['title' , 'content' ]); $data = $request ->except (['_token' ]); if ($request ->has ('title' )) { } if ($request ->has (['title' , 'content' ])) { } if ($request ->filled ('title' )) { } if ($request ->missing ('title' )) { } Post ::create ($data ); return redirect ()->route ('posts.index' ); }
6.2 Laravel 12 表单验证 Laravel 12 提供了多种表单验证方法,包括控制器验证、请求类验证等,帮助我们确保用户输入的数据符合要求。
Laravel 12 控制器验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 use Illuminate \Http \Request ;use Illuminate \Validation \ValidationException ;use Illuminate \Support \Facades \Validator ;public function store (Request $request ) { $rules = [ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , ]; $messages = [ 'title.required' => 'Title is required' , 'title.min' => 'Title must be at least 3 characters' , 'content.required' => 'Content is required' , 'content.min' => 'Content must be at least 10 characters' , ]; $attributes = [ 'title' => 'Post Title' , 'content' => 'Post Content' , ]; $request ->validate ($rules , $messages , $attributes ); Post ::create ($request ->all ()); return redirect ()->route ('posts.index' ); }
Laravel 12 请求类验证 Laravel 12 请求类验证是一种更优雅的验证方式,它将验证逻辑从控制器中分离出来,使代码更加清晰和可维护。
1 2 php artisan make:request StorePostRequest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 namespace App \Http \Requests ;use Illuminate \Foundation \Http \FormRequest ;class StorePostRequest extends FormRequest { public function authorize ( ) { return true ; } public function rules ( ) { return [ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , ]; } public function messages ( ) { return [ 'title.required' => 'Title is required' , 'title.min' => 'Title must be at least 3 characters' , 'content.required' => 'Content is required' , 'content.min' => 'Content must be at least 10 characters' , ]; } public function attributes ( ) { return [ 'title' => 'Post Title' , 'content' => 'Post Content' , ]; } }
Laravel 12 在控制器中使用请求类:
1 2 3 4 5 6 7 8 9 10 11 12 13 use App \Http \Requests \StorePostRequest ;public function store (StorePostRequest $request ) { Post ::create ($request ->validated ()); return redirect ()->route ('posts.index' ); }
Laravel 12 验证规则 Laravel 12 提供了丰富的验证规则,帮助我们确保用户输入的数据符合要求:
规则 描述 required 字段必须存在且不为空 min 字符串长度或数值最小值 max 字符串长度或数值最大值 email 必须是有效的电子邮件地址 unique 必须在指定表中是唯一的 exists 必须在指定表中存在 regex 必须匹配指定的正则表达式 confirmed 必须与同名的 _confirmed 字段值匹配 nullable 字段可以为空 date 必须是有效的日期 boolean 必须是布尔值 numeric 必须是数值 integer 必须是整数 alpha 必须只包含字母 alpha_dash 必须只包含字母、数字、破折号和下划线 alpha_num 必须只包含字母和数字 url 必须是有效的 URL ip 必须是有效的 IP 地址 json 必须是有效的 JSON 字符串
Laravel 12 验证规则非常强大,可以组合使用多个规则来满足复杂的验证需求。例如:
1 2 3 4 5 'title' => 'required|min:3|max:255|unique:posts' ,'email' => 'required|email|unique:users' ,'password' => 'required|min:8|confirmed' ,'age' => 'required|integer|min:18|max:100' ,
Laravel 12 显示验证错误 在 Laravel 12 视图中,我们可以使用 $errors 变量来显示验证错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <form action ="{{ route('posts.store') }}" method ="POST" > @csrf <div class ="mb-3" > <label for ="title" class ="form-label" > Title</label > <input type ="text" class ="form-control @error('title') is-invalid @enderror" id ="title" name ="title" value ="{{ old('title') }}" required > @error('title') <div class ="invalid-feedback" > {{ $message }} </div > @enderror </div > <div class ="mb-3" > <label for ="content" class ="form-label" > Content</label > <textarea class ="form-control @error('content') is-invalid @enderror" id ="content" name ="content" rows ="3" required > {{ old('content') }}</textarea > @error('content') <div class ="invalid-feedback" > {{ $message }} </div > @enderror </div > <button type ="submit" class ="btn btn-primary" > Submit</button > </form >
Laravel 12 提供了以下用于显示验证错误的方法:
@error 指令:用于检查特定字段的错误$errors->any():检查是否有任何错误$errors->all():获取所有错误消息$errors->get('field'):获取特定字段的错误消息old('field'):获取之前输入的值,用于表单回显1 2 3 4 5 6 7 8 #### Laravel 12 自定义验证规则 Laravel 12 允许我们创建自定义验证规则,以满足特定的验证需求: ```bash # Laravel 12 创建验证规则 php artisan make:rule Uppercase
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 namespace App \Rules ;use Illuminate \Contracts \Validation \Rule ;class Uppercase implements Rule { public function passes ($attribute , $value ) { return strtoupper ($value ) === $value ; } public function message ( ) { return 'The :attribute must be uppercase.' ; } }
Laravel 12 使用自定义验证规则:
1 2 3 4 5 6 7 8 9 10 11 use App \Rules \Uppercase ;public function rules ( ) { return [ 'title' => ['required' , new Uppercase ], ]; }
Laravel 12 自定义验证规则非常灵活,可以根据具体的业务需求创建各种复杂的验证规则,提高应用的安全性和可靠性。
6.3 Laravel 12 CSRF 保护 CSRF(Cross-Site Request Forgery)是一种常见的 Web 攻击方式,Laravel 12 提供了内置的 CSRF 保护,帮助我们防止恶意网站伪造请求。
Laravel 12 添加 CSRF 令牌 在 Laravel 12 表单中,我们需要添加 CSRF 令牌:
1 2 3 4 5 <form action ="{{ route('posts.store') }}" method ="POST" > @csrf </form >
Laravel 12 AJAX 请求中的 CSRF 保护 对于 Laravel 12 AJAX 请求,我们可以在请求头中添加 CSRF 令牌:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <meta name="csrf-token" content="{{ csrf_token() }}" > $.ajaxSetup ({ headers : { 'X-CSRF-TOKEN' : $('meta[name="csrf-token"]' ).attr ('content' ) } }); $.ajax ({ url : '/posts' , type : 'POST' , data : { title : 'Test' , content : 'Test content' }, headers : { 'X-CSRF-TOKEN' : $('meta[name="csrf-token"]' ).attr ('content' ) }, success : function (response ) { console .log (response); } });
Laravel 12 排除路由的 CSRF 保护 在某些情况下,我们可能需要排除某些路由的 CSRF 保护,例如 API 路由:
1 2 3 4 5 protected $except = [ 'api/*' , 'webhook/*' , ];
6.4 请求类 请求类不仅可以用于验证,还可以用于处理请求数据的转换和准备。
自定义请求类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 namespace App \Http \Requests ;use Illuminate \Foundation \Http \FormRequest ;class StorePostRequest extends FormRequest { public function authorize ( ) { return true ; } public function rules ( ) { return [ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , ]; } protected function prepareForValidation ( ) { $this ->merge ([ 'title' => trim ($this ->title), 'content' => trim ($this ->content), ]); } public function validated ( ) { return array_merge (parent ::validated (), [ 'slug' => str_slug ($this ->title), ]); } }
6.5 表单数据持久化 当表单验证失败时,我们通常希望保持用户已经输入的数据,Laravel 提供了 old() 辅助函数来实现这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <input type ="text" class ="form-control" id ="title" name ="title" value ="{{ old('title') }}" required > <textarea class ="form-control" id ="content" name ="content" rows ="3" required > {{ old('content') }}</textarea > <select class ="form-select" name ="category" required > <option value ="" > Select Category</option > <option value ="1" {{ old ('category ') == 1 ? 'selected ' : '' }}> Category 1</option > <option value ="2" {{ old ('category ') == 2 ? 'selected ' : '' }}> Category 2</option > </select > <input type ="radio" id ="status-active" name ="status" value ="active" {{ old ('status ') == 'active' ? 'checked ' : '' }}> <label for ="status-active" > Active</label > <input type ="radio" id ="status-inactive" name ="status" value ="inactive" {{ old ('status ') == 'inactive' ? 'checked ' : '' }}> <label for ="status-inactive" > Inactive</label > <input type ="checkbox" id ="featured" name ="featured" {{ old ('featured ') ? 'checked ' : '' }}> <label for ="featured" > Featured</label >
6.6 实战示例 现在,让我们为之前创建的博客应用添加表单验证:
创建请求类
1 2 php artisan make:request StorePostRequest php artisan make:request UpdatePostRequest
编辑 StorePostRequest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 namespace App \Http \Requests ;use Illuminate \Foundation \Http \FormRequest ;class StorePostRequest extends FormRequest { public function authorize ( ) { return true ; } public function rules ( ) { return [ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , ]; } }
编辑 UpdatePostRequest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 namespace App \Http \Requests ;use Illuminate \Foundation \Http \FormRequest ;class UpdatePostRequest extends FormRequest { public function authorize ( ) { return true ; } public function rules ( ) { return [ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , ]; } }
更新控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 use App \Http \Requests \StorePostRequest ;use App \Http \Requests \UpdatePostRequest ;public function store (StorePostRequest $request ) { Post ::create ($request ->validated ()); return redirect ()->route ('posts.index' ); } public function update (UpdatePostRequest $request , Post $post ) { $post ->update ($request ->validated ()); return redirect ()->route ('posts.show' , $post ); }
更新视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <form action ="{{ route('posts.store') }}" method ="POST" > @csrf <div class ="mb-3" > <label for ="title" class ="form-label" > Title</label > <input type ="text" class ="form-control @error('title') is-invalid @enderror" id ="title" name ="title" value ="{{ old('title') }}" required > @error('title') <div class ="invalid-feedback" > {{ $message }} </div > @enderror </div > <div class ="mb-3" > <label for ="content" class ="form-label" > Content</label > <textarea class ="form-control @error('content') is-invalid @enderror" id ="content" name ="content" rows ="3" required > {{ old('content') }}</textarea > @error('content') <div class ="invalid-feedback" > {{ $message }} </div > @enderror </div > <button type ="submit" class ="btn btn-primary" > Submit</button > </form >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <form action ="{{ route('posts.update', $post) }}" method ="POST" > @csrf @method('PUT') <div class ="mb-3" > <label for ="title" class ="form-label" > Title</label > <input type ="text" class ="form-control @error('title') is-invalid @enderror" id ="title" name ="title" value ="{{ old('title', $post->title) }}" required > @error('title') <div class ="invalid-feedback" > {{ $message }} </div > @enderror </div > <div class ="mb-3" > <label for ="content" class ="form-label" > Content</label > <textarea class ="form-control @error('content') is-invalid @enderror" id ="content" name ="content" rows ="3" required > {{ old('content', $post->content) }}</textarea > @error('content') <div class ="invalid-feedback" > {{ $message }} </div > @enderror </div > <button type ="submit" class ="btn btn-primary" > Update</button > <a href ="{{ route('posts.show', $post) }}" class ="btn btn-secondary" > Cancel</a > </form >
现在,我们的博客应用已经具备了完整的表单处理功能,包括表单验证和 CSRF 保护。
6.7 高级表单处理 复杂表单 对于复杂的表单,我们可以使用嵌套字段和数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <form action ="{{ route('users.store') }}" method ="POST" > @csrf <div class ="mb-3" > <label for ="name" class ="form-label" > Name</label > <input type ="text" class ="form-control" id ="name" name ="name" required > </div > <div class ="mb-3" > <label class ="form-label" > Address</label > <div class ="row" > <div class ="col" > <input type ="text" class ="form-control" name ="address[street]" placeholder ="Street" > </div > <div class ="col" > <input type ="text" class ="form-control" name ="address[city]" placeholder ="City" > </div > <div class ="col" > <input type ="text" class ="form-control" name ="address[zip]" placeholder ="Zip Code" > </div > </div > </div > <button type ="submit" class ="btn btn-primary" > Submit</button > </form >
在控制器中获取嵌套字段:
1 2 3 4 5 6 7 8 9 10 public function store (Request $request ) { $name = $request ->input ('name' ); $address = $request ->input ('address' ); $street = $request ->input ('address.street' ); $city = $request ->input ('address.city' ); $zip = $request ->input ('address.zip' ); }
动态表单 对于动态表单,我们可以使用 JavaScript 来添加和删除表单字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 <form action ="{{ route('products.store') }}" method ="POST" > @csrf <div class ="mb-3" > <label for ="name" class ="form-label" > Product Name</label > <input type ="text" class ="form-control" id ="name" name ="name" required > </div > <div class ="mb-3" > <label class ="form-label" > Variations</label > <div id ="variations" > <div class ="variation row mb-2" > <div class ="col" > <input type ="text" class ="form-control" name ="variations[0][name]" placeholder ="Variation Name" > </div > <div class ="col" > <input type ="number" class ="form-control" name ="variations[0][price]" placeholder ="Price" > </div > <div class ="col-auto" > <button type ="button" class ="btn btn-danger remove-variation" > Remove</button > </div > </div > </div > <button type ="button" class ="btn btn-primary mt-2" id ="add-variation" > Add Variation</button > </div > <button type ="submit" class ="btn btn-primary" > Submit</button > </form > <script > document .addEventListener ('DOMContentLoaded' , function ( ) { let variationIndex = 1 ; document .getElementById ('add-variation' ).addEventListener ('click' , function ( ) { const variationsContainer = document .getElementById ('variations' ); const variationDiv = document .createElement ('div' ); variationDiv.className = 'variation row mb-2' ; variationDiv.innerHTML = ` <div class="col"> <input type="text" class="form-control" name="variations[${variationIndex} ][name]" placeholder="Variation Name"> </div> <div class="col"> <input type="number" class="form-control" name="variations[${variationIndex} ][price]" placeholder="Price"> </div> <div class="col-auto"> <button type="button" class="btn btn-danger remove-variation">Remove</button> </div> ` ; variationsContainer.appendChild (variationDiv); variationDiv.querySelector ('.remove-variation' ).addEventListener ('click' , function ( ) { variationDiv.remove (); }); variationIndex++; }); document .querySelectorAll ('.remove-variation' ).forEach (button => { button.addEventListener ('click' , function ( ) { this .closest ('.variation' ).remove (); }); }); }); </script >
在控制器中处理动态表单数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public function store (Request $request ) { $name = $request ->input ('name' ); $variations = $request ->input ('variations' ); foreach ($variations as $variation ) { $variationName = $variation ['name' ]; $variationPrice = $variation ['price' ]; } }
现在,我们已经了解了 Laravel 的表单处理,接下来我们将学习 Laravel 的认证系统。
7. 认证系统 认证系统是 Web 应用中的重要组成部分,Laravel 提供了强大的内置认证功能,包括用户注册、登录、密码重置等。
7.1 认证系统基础 Laravel 的认证系统基于以下组件:
认证控制器 :处理用户注册、登录、密码重置等请求认证中间件 :保护需要认证的路由认证视图 :提供用户界面用户模型 :存储用户信息密码哈希 :安全存储密码7.2 快速开始 Laravel 提供了 auth 命令来快速生成认证系统:
1 2 3 4 5 6 7 8 9 10 11 php artisan make:auth composer require laravel/jetstream php artisan jetstream:install livewire php artisan jetstream:install inertia php artisan migrate
7.3 手动实现认证 如果我们需要更灵活的认证系统,可以手动实现认证功能。
1. 用户模型 Laravel 已经默认包含了 User 模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 namespace App \Models ;use Illuminate \Contracts \Auth \MustVerifyEmail ;use Illuminate \Database \Eloquent \Factories \HasFactory ;use Illuminate \Foundation \Auth \User as Authenticatable ;use Illuminate \Notifications \Notifiable ;class User extends Authenticatable { use HasFactory , Notifiable ; protected $fillable = [ 'name' , 'email' , 'password' , ]; protected $hidden = [ 'password' , 'remember_token' , ]; protected $casts = [ 'email_verified_at' => 'datetime' , ]; }
2. 认证路由 我们可以在 routes/web.php 中定义认证路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Route ::get ('/register' , [AuthController ::class , 'showRegistrationForm' ])->name ('register' );Route ::post ('/register' , [AuthController ::class , 'register' ]);Route ::get ('/login' , [AuthController ::class , 'showLoginForm' ])->name ('login' );Route ::post ('/login' , [AuthController ::class , 'login' ]);Route ::post ('/logout' , [AuthController ::class , 'logout' ])->name ('logout' );Route ::get ('/password/reset' , [ForgotPasswordController ::class , 'showLinkRequestForm' ])->name ('password.request' );Route ::post ('/password/email' , [ForgotPasswordController ::class , 'sendResetLinkEmail' ])->name ('password.email' );Route ::get ('/password/reset/{token}' , [ResetPasswordController ::class , 'showResetForm' ])->name ('password.reset' );Route ::post ('/password/reset' , [ResetPasswordController ::class , 'reset' ])->name ('password.update' );Route ::middleware ('auth' )->group (function () { Route ::get ('/dashboard' , [DashboardController ::class , 'index' ])->name ('dashboard' ); });
3. 认证控制器 我们可以创建认证控制器:
1 2 3 4 php artisan make:controller AuthController php artisan make:controller ForgotPasswordController php artisan make:controller ResetPasswordController
认证控制器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 namespace App \Http \Controllers ;use App \Models \User ;use Illuminate \Http \Request ;use Illuminate \Support \Facades \Auth ;use Illuminate \Support \Facades \Hash ;class AuthController extends Controller { public function showRegistrationForm ( ) { return view ('auth.register' ); } public function register (Request $request ) { $request ->validate ([ 'name' => 'required|string|max:255' , 'email' => 'required|string|email|max:255|unique:users' , 'password' => 'required|string|min:8|confirmed' , ]); $user = User ::create ([ 'name' => $request ->name, 'email' => $request ->email, 'password' => Hash ::make ($request ->password), ]); Auth ::login ($user ); return redirect ()->route ('dashboard' ); } public function showLoginForm ( ) { return view ('auth.login' ); } public function login (Request $request ) { $request ->validate ([ 'email' => 'required|string|email' , 'password' => 'required|string' , ]); if (Auth ::attempt (['email' => $request ->email, 'password' => $request ->password])) { return redirect ()->intended ('dashboard' ); } return back ()->withErrors ([ 'email' => 'The provided credentials do not match our records.' , ]); } public function logout (Request $request ) { Auth ::logout (); $request ->session ()->invalidate (); $request ->session ()->regenerateToken (); return redirect ('/' ); } }
密码重置控制器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 namespace App \Http \Controllers ;use Illuminate \Http \Request ;use Illuminate \Support \Facades \Password ;class ForgotPasswordController extends Controller { public function showLinkRequestForm ( ) { return view ('auth.forgot-password' ); } public function sendResetLinkEmail (Request $request ) { $request ->validate (['email' => 'required|email' ]); $status = Password ::sendResetLink ( $request ->only ('email' ) ); return $status === Password ::RESET_LINK_SENT ? back ()->with (['status' => __ ($status )]) : back ()->withErrors (['email' => __ ($status )]); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 namespace App \Http \Controllers ;use Illuminate \Http \Request ;use Illuminate \Support \Facades \Password ;class ResetPasswordController extends Controller { public function showResetForm (Request $request , $token = null ) { return view ('auth.reset-password' )->with ( ['token' => $token , 'email' => $request ->email] ); } public function reset (Request $request ) { $request ->validate ([ 'token' => 'required' , 'email' => 'required|email' , 'password' => 'required|min:8|confirmed' , ]); $status = Password ::reset ( $request ->only ('email' , 'password' , 'password_confirmation' , 'token' ), function ($user , $password ) { $user ->forceFill ([ 'password' => Hash ::make ($password ) ])->save (); } ); return $status === Password ::PASSWORD_RESET ? redirect ()->route ('login' )->with ('status' , __ ($status )) : back ()->withErrors (['email' => [__ ($status )]]); } }
4. 认证视图 我们需要创建认证视图:
注册视图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Register') }}</div > <div class ="card-body" > <form method ="POST" action ="{{ route('register') }}" > @csrf <div class ="row mb-3" > <label for ="name" class ="col-md-4 col-form-label text-md-end" > {{ __('Name') }}</label > <div class ="col-md-6" > <input id ="name" type ="text" class ="form-control @error('name') is-invalid @enderror" name ="name" value ="{{ old('name') }}" required autocomplete ="name" autofocus > @error('name') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <label for ="email" class ="col-md-4 col-form-label text-md-end" > {{ __('Email Address') }}</label > <div class ="col-md-6" > <input id ="email" type ="email" class ="form-control @error('email') is-invalid @enderror" name ="email" value ="{{ old('email') }}" required autocomplete ="email" > @error('email') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <label for ="password" class ="col-md-4 col-form-label text-md-end" > {{ __('Password') }}</label > <div class ="col-md-6" > <input id ="password" type ="password" class ="form-control @error('password') is-invalid @enderror" name ="password" required autocomplete ="new-password" > @error('password') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <label for ="password-confirm" class ="col-md-4 col-form-label text-md-end" > {{ __('Confirm Password') }}</label > <div class ="col-md-6" > <input id ="password-confirm" type ="password" class ="form-control" name ="password_confirmation" required autocomplete ="new-password" > </div > </div > <div class ="row mb-0" > <div class ="col-md-6 offset-md-4" > <button type ="submit" class ="btn btn-primary" > {{ __('Register') }} </button > </div > </div > </form > </div > </div > </div > </div > </div > @endsection
登录视图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Login') }}</div > <div class ="card-body" > <form method ="POST" action ="{{ route('login') }}" > @csrf <div class ="row mb-3" > <label for ="email" class ="col-md-4 col-form-label text-md-end" > {{ __('Email Address') }}</label > <div class ="col-md-6" > <input id ="email" type ="email" class ="form-control @error('email') is-invalid @enderror" name ="email" value ="{{ old('email') }}" required autocomplete ="email" autofocus > @error('email') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <label for ="password" class ="col-md-4 col-form-label text-md-end" > {{ __('Password') }}</label > <div class ="col-md-6" > <input id ="password" type ="password" class ="form-control @error('password') is-invalid @enderror" name ="password" required autocomplete ="current-password" > @error('password') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <div class ="col-md-6 offset-md-4" > <div class ="form-check" > <input class ="form-check-input" type ="checkbox" name ="remember" id ="remember" {{ old ('remember ') ? 'checked ' : '' }}> <label class ="form-check-label" for ="remember" > {{ __('Remember Me') }} </label > </div > </div > </div > <div class ="row mb-0" > <div class ="col-md-8 offset-md-4" > <button type ="submit" class ="btn btn-primary" > {{ __('Login') }} </button > @if (Route::has('password.request')) <a class ="btn btn-link" href ="{{ route('password.request') }}" > {{ __('Forgot Your Password?') }} </a > @endif </div > </div > </form > </div > </div > </div > </div > </div > @endsection
密码重置视图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Forgot Your Password?') }}</div > <div class ="card-body" > <form method ="POST" action ="{{ route('password.email') }}" > @csrf <div class ="row mb-3" > <label for ="email" class ="col-md-4 col-form-label text-md-end" > {{ __('Email Address') }}</label > <div class ="col-md-6" > <input id ="email" type ="email" class ="form-control @error('email') is-invalid @enderror" name ="email" value ="{{ old('email') }}" required autocomplete ="email" autofocus > @error('email') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-0" > <div class ="col-md-6 offset-md-4" > <button type ="submit" class ="btn btn-primary" > {{ __('Send Password Reset Link') }} </button > </div > </div > </form > </div > </div > </div > </div > </div > @endsection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Reset Password') }}</div > <div class ="card-body" > <form method ="POST" action ="{{ route('password.update') }}" > @csrf <input type ="hidden" name ="token" value ="{{ $token }}" > <div class ="row mb-3" > <label for ="email" class ="col-md-4 col-form-label text-md-end" > {{ __('Email Address') }}</label > <div class ="col-md-6" > <input id ="email" type ="email" class ="form-control @error('email') is-invalid @enderror" name ="email" value ="{{ $email ?? old('email') }}" required autocomplete ="email" autofocus > @error('email') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <label for ="password" class ="col-md-4 col-form-label text-md-end" > {{ __('Password') }}</label > <div class ="col-md-6" > <input id ="password" type ="password" class ="form-control @error('password') is-invalid @enderror" name ="password" required autocomplete ="new-password" > @error('password') <span class ="invalid-feedback" role ="alert" > <strong > {{ $message }}</strong > </span > @enderror </div > </div > <div class ="row mb-3" > <label for ="password-confirm" class ="col-md-4 col-form-label text-md-end" > {{ __('Confirm Password') }}</label > <div class ="col-md-6" > <input id ="password-confirm" type ="password" class ="form-control" name ="password_confirmation" required autocomplete ="new-password" > </div > </div > <div class ="row mb-0" > <div class ="col-md-6 offset-md-4" > <button type ="submit" class ="btn btn-primary" > {{ __('Reset Password') }} </button > </div > </div > </form > </div > </div > </div > </div > </div > @endsection
5. 仪表板控制器 我们需要创建一个仪表板控制器来显示用户登录后的页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 namespace App \Http \Controllers ;use Illuminate \Http \Request ;class DashboardController extends Controller { public function index ( ) { return view ('dashboard' ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Dashboard') }}</div > <div class ="card-body" > @if (session('status')) <div class ="alert alert-success" role ="alert" > {{ session('status') }} </div > @endif {{ __('You are logged in!') }} </div > </div > </div > </div > </div > @endsection
7.4 认证中间件 Laravel 提供了 auth 中间件来保护需要认证的路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Route ::get ('/dashboard' , [DashboardController ::class , 'index' ])->middleware ('auth' );Route ::middleware ('auth' )->group (function () { Route ::get ('/dashboard' , [DashboardController ::class , 'index' ]); Route ::get ('/profile' , [ProfileController ::class , 'index' ]); }); class DashboardController extends Controller { public function __construct ( ) { $this ->middleware ('auth' ); } }
7.5 认证辅助函数 Laravel 提供了多个认证辅助函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 if (auth ()->check ()) { } if (auth ()->guest ()) { } $user = auth ()->user ();$userId = auth ()->id ();auth ()->login ($user );auth ()->logout ();auth ()->attempt (['email' => $email , 'password' => $password ]);if (Hash ::check ($password , $user ->password)) { } $hashedPassword = Hash ::make ($password );
7.6 自定义认证 自定义认证 guard 我们可以创建自定义的认证 guard 来使用不同的认证方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 'guards' => [ 'web' => [ 'driver' => 'session' , 'provider' => 'users' , ], 'api' => [ 'driver' => 'token' , 'provider' => 'users' , ], 'admin' => [ 'driver' => 'session' , 'provider' => 'admins' , ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent' , 'model' => App\Models\User ::class , ], 'admins' => [ 'driver' => 'eloquent' , 'model' => App\Models\Admin ::class , ], ],
使用自定义 guard:
1 2 3 4 5 6 7 8 9 10 auth ('admin' )->attempt (['email' => $email , 'password' => $password ]);$admin = auth ('admin' )->user ();Route ::middleware ('auth:admin' )->group (function () { });
自定义认证字段 我们可以修改认证逻辑来使用不同的字段进行认证:
1 2 3 4 5 6 7 8 auth ()->attempt (['username' => $username , 'password' => $password ]);public function username ( ) { return 'username' ; }
7.7 邮箱验证 Laravel 提供了内置的邮箱验证功能:
1. 更新用户模型 1 2 3 4 5 class User extends Authenticatable implements MustVerifyEmail { }
2. 注册路由 1 2 3 4 Route ::get ('/email/verify' , [VerificationController ::class , 'show' ])->name ('verification.notice' );Route ::get ('/email/verify/{id}/{hash}' , [VerificationController ::class , 'verify' ])->name ('verification.verify' );Route ::post ('/email/resend' , [VerificationController ::class , 'resend' ])->name ('verification.resend' );
3. 创建验证控制器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 namespace App \Http \Controllers ;use Illuminate \Http \Request ;use Illuminate \Foundation \Auth \EmailVerificationRequest ;class VerificationController extends Controller { public function show ( ) { return view ('auth.verify-email' ); } public function verify (EmailVerificationRequest $request ) { $request ->fulfill (); return redirect ()->route ('dashboard' ); } public function resend (Request $request ) { $request ->user ()->sendEmailVerificationNotification (); return back ()->with ('message' , 'Verification link sent!' ); } }
4. 创建验证视图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Verify Your Email Address') }}</div > <div class ="card-body" > @if (session('message')) <div class ="alert alert-success" role ="alert" > {{ session('message') }} </div > @endif {{ __('Before proceeding, please check your email for a verification link.') }} {{ __('If you did not receive the email') }}, <form class ="d-inline" method ="POST" action ="{{ route('verification.resend') }}" > @csrf <button type ="submit" class ="btn btn-link p-0 m-0 align-baseline" > {{ __('click here to request another') }}</button > . </form > </div > </div > </div > </div > </div > @endsection
5. 保护需要验证的路由 1 2 3 4 Route ::middleware (['auth' , 'verified' ])->group (function () { Route ::get ('/dashboard' , [DashboardController ::class , 'index' ]); });
7.8 实战示例 现在,让我们为之前创建的博客应用添加认证功能:
创建认证控制器
1 2 php artisan make:controller AuthController php artisan make:controller DashboardController
编辑认证控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 namespace App \Http \Controllers ;use App \Models \User ;use Illuminate \Http \Request ;use Illuminate \Support \Facades \Auth ;use Illuminate \Support \Facades \Hash ;class AuthController extends Controller { public function showRegistrationForm ( ) { return view ('auth.register' ); } public function register (Request $request ) { $request ->validate ([ 'name' => 'required|string|max:255' , 'email' => 'required|string|email|max:255|unique:users' , 'password' => 'required|string|min:8|confirmed' , ]); $user = User ::create ([ 'name' => $request ->name, 'email' => $request ->email, 'password' => Hash ::make ($request ->password), ]); Auth ::login ($user ); return redirect ()->route ('dashboard' ); } public function showLoginForm ( ) { return view ('auth.login' ); } public function login (Request $request ) { $request ->validate ([ 'email' => 'required|string|email' , 'password' => 'required|string' , ]); if (Auth ::attempt (['email' => $request ->email, 'password' => $request ->password])) { return redirect ()->intended ('dashboard' ); } return back ()->withErrors ([ 'email' => 'The provided credentials do not match our records.' , ]); } public function logout (Request $request ) { Auth ::logout (); $request ->session ()->invalidate (); $request ->session ()->regenerateToken (); return redirect ('/' ); } }
编辑仪表板控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 namespace App \Http \Controllers ;use Illuminate \Http \Request ;class DashboardController extends Controller { public function __construct ( ) { $this ->middleware ('auth' ); } public function index ( ) { return view ('dashboard' ); } }
创建认证视图
创建 resources/views/auth/register.blade.php 创建 resources/views/auth/login.blade.php 创建 resources/views/dashboard.blade.php 定义路由
1 2 3 4 5 6 7 8 9 10 11 Route ::get ('/register' , [AuthController ::class , 'showRegistrationForm' ])->name ('register' );Route ::post ('/register' , [AuthController ::class , 'register' ]);Route ::get ('/login' , [AuthController ::class , 'showLoginForm' ])->name ('login' );Route ::post ('/login' , [AuthController ::class , 'login' ]);Route ::post ('/logout' , [AuthController ::class , 'logout' ])->name ('logout' );Route ::middleware ('auth' )->group (function () { Route ::get ('/dashboard' , [DashboardController ::class , 'index' ])->name ('dashboard' ); });
更新布局文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <nav class ="navbar navbar-expand-lg navbar-light bg-light" > <div class ="container" > <a class ="navbar-brand" href ="{{ route('posts.index') }}" > Blog</a > <div class ="collapse navbar-collapse" > <ul class ="navbar-nav mr-auto" > <li class ="nav-item" > <a class ="nav-link" href ="{{ route('posts.index') }}" > Home</a > </li > @auth <li class ="nav-item" > <a class ="nav-link" href ="{{ route('posts.create') }}" > Create Post</a > </li > <li class ="nav-item" > <a class ="nav-link" href ="{{ route('dashboard') }}" > Dashboard</a > </li > @endauth </ul > <ul class ="navbar-nav ml-auto" > @guest <li class ="nav-item" > <a class ="nav-link" href ="{{ route('login') }}" > Login</a > </li > <li class ="nav-item" > <a class ="nav-link" href ="{{ route('register') }}" > Register</a > </li > @else <li class ="nav-item dropdown" > <a id ="navbarDropdown" class ="nav-link dropdown-toggle" href ="#" role ="button" data-toggle ="dropdown" aria-haspopup ="true" aria-expanded ="false" > {{ Auth::user()->name }} </a > <div class ="dropdown-menu dropdown-menu-right" aria-labelledby ="navbarDropdown" > <a class ="dropdown-item" href ="{{ route('dashboard') }}" > Dashboard</a > <form method ="POST" action ="{{ route('logout') }}" > @csrf <button type ="submit" class ="dropdown-item" > Logout</button > </form > </div > </li > @endguest </ul > </div > </div > </nav >
运行迁移
现在,我们的博客应用已经具备了完整的认证功能,包括用户注册、登录和注销。
7.9 安全建议 在实现认证系统时,我们应该遵循以下安全建议:
使用密码哈希 :永远不要明文存储密码,使用 Laravel 提供的 Hash 门面来哈希密码使用 HTTPS :在生产环境中使用 HTTPS 来保护用户数据实现 CSRF 保护 :使用 Laravel 的 CSRF 保护来防止跨站请求伪造攻击限制登录尝试 :实现登录尝试限制,防止暴力破解使用安全的会话管理 :使用 Laravel 的会话管理功能实现邮箱验证 :验证用户邮箱,防止垃圾注册使用强密码策略 :要求用户使用强密码定期更新密码 :鼓励用户定期更新密码实现双因素认证 :对于敏感操作,实现双因素认证安全存储令牌 :安全存储重置密码令牌等临时令牌现在,我们已经了解了 Laravel 的认证系统,接下来我们将学习 Laravel 的文件上传和存储功能。
8. 文件上传和存储 文件上传和存储是 Web 应用中常见的功能,Laravel 提供了强大的文件处理功能,支持本地存储和云存储。
8.1 文件上传基础 1. 表单设置 要上传文件,我们需要在表单中添加 enctype="multipart/form-data" 属性:
1 2 3 4 5 6 7 8 <form method ="POST" action ="{{ route('upload') }}" enctype ="multipart/form-data" > @csrf <div class ="mb-3" > <label for ="file" class ="form-label" > Upload File</label > <input type ="file" class ="form-control" id ="file" name ="file" > </div > <button type ="submit" class ="btn btn-primary" > Upload</button > </form >
2. 处理上传 在控制器中,我们可以使用 $request->file() 方法来获取上传的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 namespace App \Http \Controllers ;use Illuminate \Http \Request ;class UploadController extends Controller { public function upload (Request $request ) { $request ->validate ([ 'file' => 'required|file|max:1024' , // 1 MB 限制 ]); $file = $request ->file ('file' ); if ($file ->isValid ()) { $path = $file ->store ('uploads' ); return back ()->with ('success' , 'File uploaded successfully!' )->with ('path' , $path ); } return back ()->with ('error' , 'File upload failed!' ); } }
3. 路由定义 1 2 3 Route ::get ('/upload' , [UploadController ::class , 'showForm' ])->name ('upload.form' );Route ::post ('/upload' , [UploadController ::class , 'upload' ])->name ('upload' );
8.2 本地存储 Laravel 的本地存储使用 storage/app 目录作为根目录。我们可以通过配置文件 config/filesystems.php 来修改存储设置。
1. 存储磁盘 Laravel 支持多种存储磁盘,默认包括:
local :本地存储,使用 storage/app 目录public :公共存储,使用 storage/app/public 目录s3 :Amazon S3 存储2. 公共存储 对于需要公开访问的文件,我们可以使用公共存储:
1 2 3 4 5 $path = $file ->store ('images' , 'public' );php artisan storage:link
创建符号链接后,我们可以通过以下 URL 访问文件:
1 <img src ="{{ asset('storage/' . $path) }}" alt ="Image" >
3. 存储路径 Laravel 提供了多个辅助函数来获取存储路径:
1 2 3 4 5 6 7 8 9 10 11 $root = storage_path ();$appPath = storage_path ('app' );$publicPath = storage_path ('app/public' );$uploadsPath = storage_path ('app/uploads' );
8.3 云存储 Laravel 支持多种云存储服务,包括 Amazon S3、Google Cloud Storage、Azure Blob Storage 等。
1. Amazon S3 安装依赖 :
1 composer require league/flysystem-aws-s3-v3
配置 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 'disks' => [ 's3' => [ 'driver' => 's3' , 'key' => env ('AWS_ACCESS_KEY_ID' ), 'secret' => env ('AWS_SECRET_ACCESS_KEY' ), 'region' => env ('AWS_DEFAULT_REGION' ), 'bucket' => env ('AWS_BUCKET' ), 'url' => env ('AWS_URL' ), 'endpoint' => env ('AWS_ENDPOINT' ), 'use_path_style_endpoint' => env ('AWS_USE_PATH_STYLE_ENDPOINT' , false ), ], ],
使用 :
1 2 3 4 5 $path = $file ->store ('images' , 's3' );$url = Storage ::disk ('s3' )->url ($path );
2. Google Cloud Storage 安装依赖 :
1 composer require league/flysystem-google-cloud-storage
配置 :
1 2 3 4 5 6 7 8 9 10 11 12 'disks' => [ 'gcs' => [ 'driver' => 'gcs' , 'project_id' => env ('GOOGLE_CLOUD_PROJECT_ID' ), 'key_file' => env ('GOOGLE_CLOUD_KEY_FILE' ), 'bucket' => env ('GOOGLE_CLOUD_STORAGE_BUCKET' ), 'path_prefix' => env ('GOOGLE_CLOUD_STORAGE_PATH_PREFIX' ), 'storage_api_uri' => env ('GOOGLE_CLOUD_STORAGE_API_URI' ), ], ],
使用 :
1 2 3 4 5 $path = $file ->store ('images' , 'gcs' );$url = Storage ::disk ('gcs' )->url ($path );
8.4 文件验证 在上传文件时,我们应该验证文件的类型、大小等属性:
1. 基本验证规则 1 2 3 4 5 6 7 8 9 10 $request ->validate ([ // 验证文件存在且是有效文件 'file' => 'required|file' , // 验证文件大小(1 MB) 'file' => 'required|file|max:1024' , // 验证文件类型 'file' => 'required|file|mimes:jpg,jpeg,png,gif' , // 验证文件类型和大小 'file' => 'required|file|mimes:jpg,jpeg,png|max:2048' , ]);
2. 自定义验证规则 我们可以创建自定义验证规则来验证文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 namespace App \Rules ;use Illuminate \Contracts \Validation \Rule ;class FileExtension implements Rule { protected $extensions ; public function __construct ($extensions ) { $this ->extensions = $extensions ; } public function passes ($attribute , $value ) { $extension = $value ->getClientOriginalExtension (); return in_array (strtolower ($extension ), $this ->extensions); } public function message ( ) { return 'The :attribute must be a file of type: ' . implode (', ' , $this ->extensions); } }
使用自定义规则 :
1 2 3 4 5 use App \Rules \FileExtension ;$request ->validate ([ 'file' => ['required' , 'file' , new FileExtension (['jpg' , 'jpeg' , 'png' ])], ]);
3. 验证图片尺寸 我们可以使用 dimensions 规则来验证图片尺寸:
1 2 3 4 5 6 7 8 9 10 $request ->validate ([ // 验证图片最小尺寸 'image' => 'required|image|dimensions:min_width=100,min_height=100' , // 验证图片最大尺寸 'image' => 'required|image|dimensions:max_width=1000,max_height=1000' , // 验证图片尺寸范围 'image' => 'required|image|dimensions:min_width=100,min_height=100,max_width=1000,max_height=1000' , // 验证图片比例 'image' => 'required|image|dimensions:ratio=16/9' , ]);
8.5 文件管理 Laravel 提供了 Storage 门面来管理文件:
1. 存储文件 1 2 3 4 5 6 7 8 9 10 11 12 13 use Illuminate \Support \Facades \Storage ;Storage ::put ('file.txt' , 'Contents' );Storage ::disk ('public' )->put ('file.txt' , 'Contents' );Storage ::putFile ('photos' , $request ->file ('photo' ));Storage ::disk ('s3' )->putFile ('photos' , $request ->file ('photo' ));
2. 读取文件 1 2 3 4 5 6 7 8 9 10 11 12 13 $contents = Storage ::get ('file.txt' );if (Storage ::exists ('file.txt' )) { } $size = Storage ::size ('file.txt' );$time = Storage ::lastModified ('file.txt' );
3. 下载文件 1 2 3 4 5 6 7 8 9 10 return Storage ::download ('file.txt' );return Storage ::download ('file.txt' , 'custom-name.txt' );return Storage ::download ('file.txt' , 'custom-name.txt' , [ 'Content-Type' => 'text/plain' , ]);
4. 删除文件 1 2 3 4 5 6 7 8 Storage ::delete ('file.txt' );Storage ::delete (['file1.txt' , 'file2.txt' ]);Storage ::deleteDirectory ('photos' );
5. 目录操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Storage ::makeDirectory ('photos' );Storage ::deleteDirectory ('photos' );$files = Storage ::files ('photos' );$files = Storage ::allFiles ('photos' );$directories = Storage ::directories ('photos' );$directories = Storage ::allDirectories ('photos' );
8.6 实战示例 现在,让我们为之前创建的博客应用添加图片上传功能:
1. 更新帖子迁移 1 2 3 4 5 6 7 8 9 10 11 public function up ( ) { Schema ::create ('posts' , function (Blueprint $table ) { $table ->id (); $table ->string ('title' ); $table ->text ('content' ); $table ->string ('image' )->nullable (); $table ->timestamps (); }); }
2. 更新帖子模型 1 2 3 4 5 6 protected $fillable = [ 'title' , 'content' , 'image' , ];
3. 更新帖子表单 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <form method ="POST" action ="{{ route('posts.store') }}" enctype ="multipart/form-data" > @csrf <div class ="mb-3" > <label for ="title" class ="form-label" > Title</label > <input type ="text" class ="form-control @error('title') is-invalid @enderror" id ="title" name ="title" value ="{{ old('title') }}" required > @error('title') <div class ="invalid-feedback" > {{ $message }}</div > @enderror </div > <div class ="mb-3" > <label for ="content" class ="form-label" > Content</label > <textarea class ="form-control @error('content') is-invalid @enderror" id ="content" name ="content" rows ="3" required > {{ old('content') }}</textarea > @error('content') <div class ="invalid-feedback" > {{ $message }}</div > @enderror </div > <div class ="mb-3" > <label for ="image" class ="form-label" > Image</label > <input type ="file" class ="form-control @error('image') is-invalid @enderror" id ="image" name ="image" > @error('image') <div class ="invalid-feedback" > {{ $message }}</div > @enderror </div > <button type ="submit" class ="btn btn-primary" > Submit</button > </form >
4. 更新帖子控制器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 use Illuminate \Http \Request ;use App \Models \Post ;class PostController extends Controller { public function store (Request $request ) { $request ->validate ([ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , 'image' => 'nullable|image|max:2048' , // 验证图片 ]); $imagePath = null ; if ($request ->hasFile ('image' )) { $imagePath = $request ->file ('image' )->store ('posts' , 'public' ); } $post = Post ::create ([ 'title' => $request ->title, 'content' => $request ->content, 'image' => $imagePath , // 存储图片路径 ]); return redirect ()->route ('posts.show' , $post ->id) ->with ('success' , 'Post created successfully!' ); } public function update (Request $request , Post $post ) { $request ->validate ([ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , 'image' => 'nullable|image|max:2048' , // 验证图片 ]); if ($request ->hasFile ('image' )) { if ($post ->image) { Storage ::disk ('public' )->delete ($post ->image); } $imagePath = $request ->file ('image' )->store ('posts' , 'public' ); } else { $imagePath = $post ->image; } $post ->update ([ 'title' => $request ->title, 'content' => $request ->content, 'image' => $imagePath , // 更新图片路径 ]); return redirect ()->route ('posts.show' , $post ->id) ->with ('success' , 'Post updated successfully!' ); } public function destroy (Post $post ) { if ($post ->image) { Storage ::disk ('public' )->delete ($post ->image); } $post ->delete (); return redirect ()->route ('posts.index' ) ->with ('success' , 'Post deleted successfully!' ); } }
5. 更新帖子视图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <h1 > {{ $post->title }}</h1 > @if ($post->image) <img src ="{{ asset('storage/' . $post->image) }}" alt ="{{ $post->title }}" class ="img-fluid mb-4" > @endif <div class ="card" > <div class ="card-body" > {{ $post->content }} </div > </div > <div class ="mt-4" > <a href ="{{ route('posts.edit', $post->id) }}" class ="btn btn-primary" > Edit</a > <form action ="{{ route('posts.destroy', $post->id) }}" method ="POST" class ="d-inline" > @csrf @method('DELETE') <button type ="submit" class ="btn btn-danger" onclick ="return confirm('Are you sure?');" > Delete</button > </form > </div > </div > </div > </div > @endsection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <h1 > Posts</h1 > @auth <a href ="{{ route('posts.create') }}" class ="btn btn-primary mb-4" > Create Post</a > @endauth @foreach ($posts as $post) <div class ="card mb-4" > @if ($post->image) <img src ="{{ asset('storage/' . $post->image) }}" alt ="{{ $post->title }}" class ="card-img-top" > @endif <div class ="card-body" > <h2 class ="card-title" > {{ $post->title }}</h2 > <p class ="card-text" > {{ Str::limit($post->content, 100) }}</p > <a href ="{{ route('posts.show', $post->id) }}" class ="btn btn-primary" > Read More</a > </div > </div > @endforeach </div > </div > </div > @endsection
6. 创建符号链接 1 php artisan storage:link
现在,我们的博客应用已经具备了图片上传功能,用户可以在创建和编辑帖子时上传图片。
8.7 安全建议 在实现文件上传功能时,我们应该遵循以下安全建议:
验证文件类型 :使用 mimes 或 image 规则验证文件类型限制文件大小 :使用 max 规则限制文件大小,防止上传过大的文件重命名文件 :使用 storeAs 方法重命名上传的文件,避免文件名冲突和安全问题使用安全的存储位置 :对于敏感文件,使用本地存储而不是公共存储扫描上传的文件 :使用第三方库扫描上传的文件,防止恶意文件设置适当的文件权限 :确保存储目录有适当的文件权限使用 HTTPS :在生产环境中使用 HTTPS 传输文件实现文件上传速率限制 :防止恶意用户上传大量文件使用内容安全策略 :限制可以从哪些来源加载文件定期清理未使用的文件 :定期清理未使用的上传文件,节省存储空间8.8 高级技巧 1. 图片处理 我们可以使用 intervention/image 库来处理图片:
安装依赖 :
1 composer require intervention/image
配置 :
1 2 3 4 5 6 7 8 9 10 'providers' => [ Intervention\Image\ImageServiceProvider ::class , ], 'aliases' => [ 'Image' => Intervention\Image\Facades\Image ::class , ],
使用 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 use Intervention \Image \Facades \Image ;if ($request ->hasFile ('image' )) { $image = $request ->file ('image' ); $filename = time () . '.' . $image ->getClientOriginalExtension (); Image ::make ($image )->resize (800 , 600 , function ($constraint ) { $constraint ->aspectRatio (); $constraint ->upsize (); })->save (public_path ('storage/posts/' . $filename )); $imagePath = 'posts/' . $filename ; }
2. 多文件上传 我们可以使用数组形式的文件输入来上传多个文件:
1 2 3 4 5 6 7 8 <form method ="POST" action ="{{ route('upload.multiple') }}" enctype ="multipart/form-data" > @csrf <div class ="mb-3" > <label for ="files" class ="form-label" > Upload Files</label > <input type ="file" class ="form-control" id ="files" name ="files[]" multiple > </div > <button type ="submit" class ="btn btn-primary" > Upload</button > </form >
处理多文件上传 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public function uploadMultiple (Request $request ) { $request ->validate ([ 'files.*' => 'required|file|max:1024' , ]); $paths = []; foreach ($request ->file ('files' ) as $file ) { $paths [] = $file ->store ('uploads' , 'public' ); } return back ()->with ('success' , 'Files uploaded successfully!' )->with ('paths' , $paths ); }
3. 远程文件上传 我们可以使用 Storage 门面来上传远程文件:
1 2 3 4 5 6 7 8 use Illuminate \Support \Facades \Storage ;use Illuminate \Support \Facades \Http ;$response = Http ::get ('https://example.com/image.jpg' );Storage ::put ('remote-image.jpg' , $response ->body ());
现在,我们已经了解了 Laravel 的文件上传和存储功能,接下来我们将学习 Laravel 的部署方法。
9. 部署 部署是将 Laravel 应用从开发环境转移到生产环境的过程。在本章节中,我们将学习如何部署 Laravel 应用到不同的环境。
9.1 本地服务器 在开发过程中,我们可以使用 Laravel 内置的开发服务器来测试应用:
1 2 3 4 5 6 7 8 php artisan serve php artisan serve --port=8080 php artisan serve --host=0.0.0.0 --port=8080
开发服务器默认运行在 http://localhost:8000。
9.2 Laravel Valet Laravel Valet 是为 macOS 设计的轻量级开发环境,提供了快速的本地开发体验:
1. 安装 Valet 1 2 3 4 5 6 7 8 9 10 11 12 13 composer global require laravel/valet valet install cd ~/Sitesvalet park cd ~/Sites/laravel-appvalet link
2. 使用 Valet 1 2 3 4 5 6 7 8 9 10 11 valet sites valet restart valet stop valet uninstall
9.3 部署前准备 在部署 Laravel 应用之前,我们需要进行一些准备工作:
1. 环境变量 确保在 .env 文件中设置了正确的环境变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # 应用配置 APP_NAME="Laravel" APP_ENV=production APP_KEY= APP_DEBUG=false APP_URL=https://example.com # 数据库配置 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD= # 邮件配置 MAIL_MAILER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}"
2. 生成应用密钥 1 2 php artisan key:generate
3. 运行迁移 1 2 3 4 5 php artisan migrate --force php artisan db:seed --force
4. 优化应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 php artisan config:cache php artisan route:cache php artisan view:cache php artisan cache:clear php artisan clear-compiled composer dump-autoload --optimize
9.4 生产环境部署 1. 使用 Git 我们可以使用 Git 来部署 Laravel 应用:
步骤 1:在服务器上初始化 Git 仓库
1 2 3 4 5 6 mkdir -p /var/www/laravel-appcd /var/www/laravel-appgit init --bare
步骤 2:创建 post-receive 钩子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 mkdir -p /var/www/laravel-app/hookscat > /var/www/laravel-app/hooks/post-receive << 'EOF' TARGET_DIR="/var/www/html/laravel-app" mkdir -p "$TARGET_DIR " cd "$TARGET_DIR " GIT_WORK_TREE="$TARGET_DIR " git checkout -f composer install --optimize-autoloader --no-dev php artisan key:generate --force php artisan migrate --force php artisan config:cache php artisan route:cache php artisan view:cache chown -R www-data:www-data "$TARGET_DIR " chmod -R 755 "$TARGET_DIR /storage" chmod -R 755 "$TARGET_DIR /bootstrap/cache" systemctl restart php8.1-fpm EOF chmod +x /var/www/laravel-app/hooks/post-receive
步骤 3:在本地添加远程仓库
1 2 3 4 5 git remote add production ssh://user@server:/var/www/laravel-app git push production master
2. 使用 Laravel Envoyer Laravel Envoyer 是一个自动化部署服务,可以轻松部署 Laravel 应用:
步骤 1:创建 Envoyer 项目
登录 Laravel Envoyer 创建新项目 连接到 GitHub、GitLab 或 Bitbucket 仓库 步骤 2:配置服务器
添加服务器 设置部署路径 配置 SSH 密钥 步骤 3:配置部署钩子
设置部署前钩子 设置部署后钩子 配置通知 步骤 4:部署应用
触发部署 监控部署过程 查看部署日志 3. 使用 Laravel Forge Laravel Forge 是一个服务器管理和部署服务,可以轻松创建和管理服务器:
步骤 1:创建 Forge 账户
登录 Laravel Forge 连接到服务器提供商(DigitalOcean、AWS、Linode 等) 步骤 2:创建服务器
选择服务器提供商 配置服务器规格 部署服务器 步骤 3:创建站点
添加新站点 配置域名 连接到 Git 仓库 步骤 4:部署应用
触发部署 配置环境变量 运行迁移 9.5 服务器配置 1. Nginx 配置 基本配置 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 server { listen 80 ; server_name example.com; root /var/www/html/laravel-app/public; add_header X-Frame-Options "SAMEORIGIN" ; add_header X-Content-Type-Options "nosniff" ; index index.php; charset utf-8 ; location / { try_files $uri $uri / /index.php?$query_string ; } location = /favicon.ico { access_log off ; log_not_found off ; } location = /robots.txt { access_log off ; log_not_found off ; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root $fastcgi_script_name ; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } }
使用 HTTPS :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 server { listen 80 ; server_name example.com; return 301 https://$host $request_uri ; } server { listen 443 ssl http2; server_name example.com; root /var/www/html/laravel-app/public; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3 ; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384; ssl_prefer_server_ciphers off ; ssl_session_cache shared:SSL:10m ; ssl_session_timeout 10m ; add_header X-Frame-Options "SAMEORIGIN" ; add_header X-Content-Type-Options "nosniff" ; add_header X-XSS-Protection "1; mode=block" ; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; index index.php; charset utf-8 ; location / { try_files $uri $uri / /index.php?$query_string ; } location = /favicon.ico { access_log off ; log_not_found off ; } location = /robots.txt { access_log off ; log_not_found off ; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root $fastcgi_script_name ; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } }
2. Apache 配置 基本配置 :
1 2 3 4 5 6 7 8 9 10 11 12 13 <VirtualHost *:80 > ServerName example.com DocumentRoot /var/www/html/laravel-app/public <Directory /var/www/html/laravel-app/public> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR} /laravel-app-error.log CustomLog ${APACHE_LOG_DIR} /laravel-app-access.log combined </VirtualHost>
使用 HTTPS :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <VirtualHost *:80 > ServerName example.com Redirect permanent / https://example.com/ </VirtualHost> <VirtualHost *:443 > ServerName example.com DocumentRoot /var/www/html/laravel-app/public SSLEngine on SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem <Directory /var/www/html/laravel-app/public> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR} /laravel-app-error.log CustomLog ${APACHE_LOG_DIR} /laravel-app-access.log combined </VirtualHost>
9.5 数据库配置 1. MySQL 安装 MySQL :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apt update apt install mysql-server mysql_secure_installation mysql -u root -p CREATE DATABASE laravel_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'laravel_user' @'localhost' IDENTIFIED BY 'password' ; GRANT ALL PRIVILEGES ON laravel_app.* TO 'laravel_user' @'localhost' ; FLUSH PRIVILEGES; EXIT;
配置 Laravel :
1 2 3 4 5 6 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_app DB_USERNAME=laravel_user DB_PASSWORD=password
2. PostgreSQL 安装 PostgreSQL :
1 2 3 4 5 6 7 8 9 10 11 12 13 apt update apt install postgresql postgresql-contrib sudo -u postgres psqlCREATE DATABASE laravel_app; CREATE USER laravel_user WITH PASSWORD 'password' ; GRANT ALL PRIVILEGES ON DATABASE laravel_app TO laravel_user; ALTER USER laravel_user WITH SUPERUSER; \q
配置 Laravel :
1 2 3 4 5 6 DB_CONNECTION=pgsql DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=laravel_app DB_USERNAME=laravel_user DB_PASSWORD=password
9.6 环境变量配置 在生产环境中,我们应该使用 .env 文件来存储敏感信息:
1. 创建 .env 文件 1 2 3 4 5 cp .env.example .env nano .env
2. 环境变量最佳实践 不要提交 .env 文件 :将 .env 文件添加到 .gitignore使用不同的环境变量 :为开发、测试和生产环境使用不同的 .env 文件使用环境变量管理服务 :如 Laravel Envoyer、AWS Parameter Store 或 HashiCorp Vault设置适当的权限 :确保 .env 文件的权限为 6009.7 优化策略 1. 缓存优化 1 2 3 4 5 6 7 8 9 10 11 php artisan config:cache php artisan route:cache php artisan view:cache php artisan cache:clear
2. 数据库优化 使用索引 :为经常查询的列添加索引使用查询构建器 :使用 Laravel 的查询构建器来优化查询使用 Eager Loading :避免 N+1 查询问题使用数据库连接池 :在高流量应用中使用连接池3. 前端优化 压缩资源 :使用 Laravel Mix 或 Vite 来压缩 CSS 和 JavaScript使用 CDN :使用内容分发网络来加速静态资源启用浏览器缓存 :设置适当的缓存头使用 HTTP/2 :启用 HTTP/2 来加速资源加载4. 服务器优化 使用 OPcache :启用 PHP OPcache 来提高性能使用 Redis :使用 Redis 作为缓存和会话存储使用队列 :将耗时任务放入队列使用负载均衡 :在高流量应用中使用负载均衡9.8 常见问题解决 1. 权限问题 问题 :storage 目录权限不足
解决 :
1 2 3 4 chown -R www-data:www-data /var/www/html/laravel-appchmod -R 755 /var/www/html/laravel-app/storagechmod -R 755 /var/www/html/laravel-app/bootstrap/cache
2. 500 错误 问题 :服务器返回 500 错误
解决 :
1 2 3 4 5 6 7 8 9 10 11 12 13 cat /var/log/nginx/error.logcat /var/log/php8.1-fpm.logcat .env php artisan key:generate php artisan cache:clear php artisan config:cache
3. 数据库连接问题 问题 :无法连接到数据库
解决 :
1 2 3 4 5 6 7 8 systemctl status mysql mysql -u laravel_user -p laravel_app cat .env
4. 路由问题 问题 :路由返回 404 错误
解决 :
1 2 3 4 5 6 7 8 9 10 11 12 php artisan route:clear php artisan route:cache php artisan route:list cat public/.htaccesscat /etc/nginx/sites-available/laravel-app
9.9 云服务部署 1. AWS 使用 AWS Elastic Beanstalk :
安装 EB CLI
初始化 EB 环境
创建环境
1 eb create production-env
部署应用
使用 AWS EC2 :
创建 EC2 实例 安装 LAMP/LEMP 堆栈 部署 Laravel 应用 配置安全组 2. DigitalOcean 使用 DigitalOcean Droplets :
创建 Droplet 选择 LAMP/LEMP 一键应用 部署 Laravel 应用 配置域名和 SSL 使用 DigitalOcean App Platform :
连接 GitHub 仓库 选择 Laravel 应用 配置环境变量 部署应用 3. Vercel 使用 Vercel :
安装 Vercel CLI
部署应用
配置环境变量
4. Heroku 使用 Heroku :
安装 Heroku CLI
登录 Heroku
创建 Heroku 应用
1 heroku create laravel-app
部署应用
配置环境变量
1 2 3 4 heroku config:set APP_KEY=$(php artisan key:generate --show) heroku config:set APP_ENV=production heroku config:set APP_DEBUG=false heroku config:set APP_URL=$(heroku apps:info -s | grep web_url | cut -d= -f2)
9.10 容器化部署 1. 使用 Docker 步骤 1:创建 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 FROM php:8.1 -fpmWORKDIR /var/www/html RUN apt-get update && apt-get install -y \ git \ curl \ libpng-dev \ libonig-dev \ libxml2-dev \ zip \ unzip \ nginx \ supervisor RUN apt-get clean && rm -rf /var/lib/apt/lists/* RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY nginx.conf /etc/nginx/nginx.conf COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY . /var/www/html RUN composer install --optimize-autoloader --no-dev RUN php artisan key:generate RUN chown -R www-data:www-data /var/www/html RUN chmod -R 755 /var/www/html/storage RUN chmod -R 755 /var/www/html/bootstrap/cache EXPOSE 80 CMD ["/usr/bin/supervisord" ]
步骤 2:创建 docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 version: '3' services: app: build: . ports: - "8000:80" volumes: - .:/var/www/html depends_on: - db db: image: mysql:8.0 environment: MYSQL_DATABASE: laravel_app MYSQL_USER: laravel_user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: root ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql volumes: mysql_data:
步骤 3:构建和运行
1 2 3 4 5 6 7 8 9 10 11 docker-compose build docker-compose up -d docker-compose logs docker-compose exec app bash
2. 使用 Docker Hub 构建镜像
1 docker build -t username/laravel-app .
推送镜像
1 docker push username/laravel-app
拉取和运行镜像
1 2 docker pull username/laravel-app docker run -p 8000:80 username/laravel-app
9.11 监控和维护 1. 日志监控 Laravel 日志 :storage/logs/laravel.log服务器日志 :/var/log/nginx/error.log、/var/log/php8.1-fpm.log使用监控服务 :如 Papertrail、Logentries 或 AWS CloudWatch2. 性能监控 使用 Laravel Telescope :在开发环境中监控应用使用 New Relic :监控生产环境性能使用 Datadog :监控服务器和应用性能使用 Blackfire :分析应用性能3. 定期维护 备份数据库 :定期备份数据库更新依赖 :定期更新 Composer 依赖更新 Laravel :定期更新 Laravel 版本清理日志 :定期清理日志文件清理缓存 :定期清理缓存9.12 实战示例 现在,让我们部署之前创建的博客应用:
1. 准备部署 1 2 3 4 5 6 7 8 9 10 11 cd laravel-appgit status git add . git commit -m "Prepare for deployment" cp .env.example .env nano .env
2. 配置服务器 安装必要的软件 :
1 2 3 4 5 6 7 8 9 apt update && apt upgrade -y apt install -y nginx php8.1 php8.1-fpm php8.1-mysql php8.1-cli php8.1-mbstring php8.1-xml php8.1-zip php8.1-gd git composer mysql-server systemctl start nginx php8.1-fpm mysql systemctl enable nginx php8.1-fpm mysql
配置数据库 :
1 2 3 4 5 6 7 8 9 mysql -u root -p CREATE DATABASE blog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'blog_user' @'localhost' IDENTIFIED BY 'password' ; GRANT ALL PRIVILEGES ON blog.* TO 'blog_user' @'localhost' ; FLUSH PRIVILEGES; EXIT;
配置 Nginx :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 cat > /etc/nginx/sites-available/blog << 'EOF' server { listen 80; server_name example.com; root /var/www/html/blog/public; add_header X-Frame-Options "SAMEORIGIN" ; add_header X-Content-Type-Options "nosniff" ; index index.php; charset utf-8; location / { try_files $uri $uri / /index.php?$query_string ; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name ; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } EOF ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/nginx -t systemctl restart nginx
3. 部署应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 mkdir -p /var/www/html/blogcd /var/www/html/bloggit clone https://github.com/username/blog.git . composer install --optimize-autoloader --no-dev cp .env.example .env nano .env php artisan key:generate php artisan migrate --force php artisan storage:link php artisan config:cache php artisan route:cache php artisan view:cache chown -R www-data:www-data /var/www/html/blogchmod -R 755 /var/www/html/blog/storagechmod -R 755 /var/www/html/blog/bootstrap/cache
4. 测试应用 现在,我们可以通过浏览器访问 http://example.com 来测试我们的博客应用。
9.13 部署最佳实践 使用版本控制 :使用 Git 来管理代码使用 CI/CD :使用持续集成和持续部署使用环境变量 :使用环境变量来存储敏感信息使用容器化 :使用 Docker 来容器化应用使用负载均衡 :在高流量应用中使用负载均衡使用 CDN :使用内容分发网络来加速静态资源使用缓存 :使用 Redis 或 Memcached 来缓存数据使用队列 :将耗时任务放入队列使用监控 :监控应用性能和错误使用备份 :定期备份数据库和文件10. 结语 恭喜你完成了《Laravel 教程 - Web 开发实战入门》的学习!在本教程中,我们学习了:
Laravel 基础 :Laravel 的历史、特点和优势环境搭建 :PHP、Composer 和 Laravel 的安装项目初始化 :Laravel 项目的创建和目录结构路由和控制器 :Laravel 的路由系统和控制器视图 :Blade 模板引擎和视图组件数据库操作 :迁移、模型、查询构建器和 Eloquent ORM表单处理 :表单验证、CSRF 保护和请求类认证系统 :用户注册、登录、密码重置和邮箱验证文件上传和存储 :本地存储、云存储和文件管理部署 :本地服务器、生产环境部署和优化策略Laravel 是一个功能强大、优雅的 PHP 框架,它提供了许多工具和功能来帮助我们快速开发 Web 应用。通过本教程的学习,你应该已经掌握了 Laravel 的核心概念和基本用法,可以开始开发自己的 Laravel 应用了。
后续学习建议 深入学习 Laravel 核心 :阅读 Laravel 官方文档,深入学习 Laravel 的核心概念和高级功能学习 Laravel 生态系统 :学习 Laravel 生态系统中的其他组件,如 Laravel Nova、Laravel Horizon、Laravel Echo 等学习前端框架 :学习 Vue.js、React 或 Angular 等前端框架,与 Laravel 结合使用学习 API 开发 :学习使用 Laravel 开发 RESTful API学习测试 :学习使用 PHPUnit 和 Laravel Dusk 进行测试参与开源项目 :参与 Laravel 或其他开源项目,提高自己的编程技能构建实际项目 :构建实际项目,将所学知识应用到实践中资源推荐 祝你在 Laravel 开发之旅中取得成功!