3.2 Laravel 实战:沿框架的月台走一遍 本节摘要:本节把 1.7 与 2.2 节的"报名表单落库"业务在 Laravel 里重新走一遍:建项目、建表(迁移)、写模型、路由、控制器、校验、中间件。每一站都标注"对应第二章哪件手工活",你会看到代码量减半的同时,结构反而更清楚。读完你应当能独立完成框架下的一条增查业务线,并理解请求在框架内的完整时序。 先建站再走线 安装走 2.7 节的采购处,一条命令拉起整个项目骨架: 是框架的站务终端,建表、建类、跑测试都从这里发令。数据库连接写在环境配置文件(根目录的那份点号 env 文件)里,填上 2.2 节用过的库名与凭证即可。 第一步建表。手写 SQL 换成"迁移"——用代码描述表结构,进版本库、可回滚: 第二步建模型。
本节摘要:本节把 1.7 与 2.2 节的"报名表单落库"业务在 Laravel 里重新走一遍:建项目、建表(迁移)、写模型、路由、控制器、校验、中间件。每一站都标注"对应第二章哪件手工活",你会看到代码量减半的同时,结构反而更清楚。读完你应当能独立完成框架下的一条增查业务线,并理解请求在框架内的完整时序。
安装走 2.7 节的采购处,一条命令拉起整个项目骨架:
composer create-project laravel/laravel station cd station php artisan serve # 内置开发服务器,默认端口 8000
artisan 是框架的站务终端,建表、建类、跑测试都从这里发令。数据库连接写在环境配置文件(根目录的那份点号 env 文件)里,填上 2.2 节用过的库名与凭证即可。
第一步建表。手写 SQL 换成"迁移"——用代码描述表结构,进版本库、可回滚:
// database/migrations/xxxx_create_passengers_table.php public function up(): void { Schema::create('passengers', function (Blueprint $table) { $table->id(); $table->string('name', 20); $table->string('email', 100)->unique(); $table->string('seat', 10)->default('economy'); $table->timestamps(); // created_at 与 updated_at 两列 }); }
php artisan migrate # 执行迁移,建出表
第二步建模型。Eloquent 是框架的 ORM:一张表对应一个模型类,一行数据对应一个对象:
// app/Models/Passenger.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Passenger extends Model { protected $fillable = ['name', 'email', 'seat']; // 允许批量赋值的白名单 }
fillable 白名单值得停一下:它决定了哪些字段可以被表单数据批量填充,没列入的字段即使恶意提交也进不了库——框架把 1.7 节"别信请求"的原则做成了机制。
路由声明"什么路径什么方法交给谁":
// routes/web.php use App\Http\Controllers\SignupController; Route::get('/signup', [SignupController::class, 'form']); // 报名页 Route::post('/signup', [SignupController::class, 'store']); // 提交受理
控制器先看代码再解读:
// app/Http/Controllers/SignupController.php namespace App\Http\Controllers; use App\Models\Passenger; use Illuminate\Http\Request; class SignupController extends Controller { public function form() { return view('signup'); // 渲染报名页模板 } public function store(Request $request) { $data = $request->validate([ // 声明式校验:不合规则自动退回 'name' => 'required|string|max:20', 'email' => 'required|email|unique:passengers,email', 'seat' => 'required|in:economy,business', ]); $passenger = Passenger::create($data); // 批量赋值进白名单字段 return redirect('/signup/done') // 重定向防重复提交 ->with('id', $passenger->id); } }
对照手工版盘账:1.7 节里"收件定型、逐项校验、统一退件"约二十行,这里收敛成 validate 一个调用——校验不过框架自动把旅客带回去并带上错误清单;unique:passengers,email 一条规则顶掉 2.2 节里捕获 23000 冲突码的手工分支;Passenger::create 内部走的正是你熟悉的预处理。代码量减半,防线一件没少。
请求在框架内的完整时序,配一张图收拢:
自写一个中间件体会洋葱模型——记录每个请求的处理耗时:
php artisan make:middleware LogTiming # 生成中间件骨架
// app/Http/Middleware/LogTiming.php public function handle(Request $request, Closure $next): Response { $start = hrtime(true); $response = $next($request); // 把请求交给管道的下一层 $costMs = (hrtime(true) - $start) / 1e6; Log::info('timing', ['path' => $request->path(), 'ms' => round($costMs, 1)]); return $response; }
$next($request) 之前是"进站段"逻辑,之后是"出站段"逻辑——与 3.1 节的洋葱描述严丝合缝。注册到全局或指定路由组后生效,2.5 节手工埋的计时点从此变成全站标配。模板层(Blade)本节只点一句:{{ $var }} 语法默认执行转义,1.7 节"出站前必转义"的纪律被做成了默认行为,忘了转义反而要特意写别的语法——好的框架让正确的事比错误的事更顺手。
⚠️ 模型里堆业务:模型管数据映射,计价与状态推进住服务类,别把 2.1 的编制纪律丢在框架门外。
⚠️ N 加一查询复发:Eloquent 的关联在循环里逐条触发查询,列表页记得用预加载(with 关键字)一次取回,2.5 节的教训在框架里照样成立。
fillable 把"别信请求"做成机制,批量赋值越界自动无视。$next 前后分别是进站段与出站段,横切逻辑一次写全站用。下一节把视野推到站网:单站容量到顶之后,微服务怎么拆、拆的代价是什么。