0. 学前准备:
- 开发环境:Laravel Sail
- IDE:VS Code
- 视频地址:【李炎恢】【Laravel / API接口 】【十天技能课堂系列】
历时三天,成功搭建Laravel Sail环境
2. 创建项目
curl -s https://laravel.build/yanhui | bash
如上所示,我创建一个名为 yanhui
的 Laravel 项目。
在 Terminal 中启动项目:
./vendor/bin/sail up
如图所示:
此时,我用浏览器打开 http://localhost/
,就可以看到以下画面,说明项目已经成功创建并且启动(这个画面我们不需要更改):
3. 创建用于 API 操作的资源控制器和对应路由
先在 Terminal 终端配置一下 Sail
命令,让它变得简短一点:
alias sail='bash vendor/bin/sail'
然后,使用以下命令创建 API 控制器
sail artisan make:controller UserController --api
--api
参数的意义是,从控制器中排除 create
和 edit
方法。
此处出现在我终端里面的 爆红 提示,是因为我在之前学习的时候已经创建过同名控制器,所以我再次演示就会这个提示,大家无视就好。
最后,我输入 code .
,使用 VS code 打开项目文件夹。
整个流程如下图所示:
至此,控制器已经创建好,接下来是对应路由,在创建路由之前,我们我们可以使用 sail artisan route:list
命令来查看一下,当前项目的路由列表是怎样的(如果你是新建的项目,应该会看到如下所示的画面):
接下来,我们打开 routes\api.php
文件,用一下代码,创建资源路由(文件原本的代码我们先不改动,注意顶部引入控制器):
<?php
use App\Http\Controllers\UserController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::apiResource('user',UserController::class);
可以看到,与原文件相比,我只添加了两句代码:
use App\Http\Controllers\UserController;
Route::apiResource('user',UserController::class);
此时,我们再次在终端中输入 sail artisan route:list
命令,可以看到如下画面:
然后,我们来测试一下:
在 app\Http\Controllers\UserControllers.php
中,我们修改 index
方法:
public function index()
{
return '你好,Laravel~';
}
然后我们用浏览器打开 http://localhost/api/user
可以看到如下画面:
最后,我们用专业的接口调试软件 Postman
打开http://localhost/api/user
可以看到以下画面:
至此,控制器和路由创建并测试成功。
4. 创建一个专门用于生成 API 的控制类,然后继承并调用它
在终端中使用命令创建控制器:
sail artisan make:controller ApiController
在生成的控制器中,我们编写一个 create
方法:(文件路径:app\Http\Controllers\ApiController.php)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ApiController extends Controller
{
protected function create($msg = '', $code = 200, $data = [])
{
$result = [
// 返回状态码
'code'=>$code,
// 返回提示信息
'msg'=>$msg,
// 返回数据
'data'=>$data,
];
return response($result);
}
}
然后,我们修改 UserController.php
文件(文件路径:app\Http\Controllers\UserController.php)
使其继承 ApiController
而不是原本的 Controller
,这样我们就可以很自然地调用 create
方法,来生成标准的 API 返回信息。
详情如下:
class UserController extends ApiController
{
public function index()
{
return $this->create('请求成功',200,'你好,Laravel~');
}
此时,我们用Postman
再次发送请求,可以看到如下画面,说明控制类创建成功。
5. 数据列表和分页
填充用户数据
在本小节,我们将真正编写第一个控制器方法的具体逻辑,但是,对于没有看前置课程的同学来说,我们也将面临一个问题:我们的数据库里面,没有任何数据。
好在,这个问题我们可以用 Laravel 的数据填充功能来解决,至于填充的原理,我就不再赘述,只讲怎么做,想进一步了解原理的同学可以阅读 Laravel 文档,或者参考本社区 《L01 Laravel 教程》的第 8 章第 4 小节。
数据填充第一步:创建 seeder 类
sail artisan make:seeder UserSeeder
生成的 UserSeeder 文件位于:database\seeders\UserSeeder.php
让我们编辑其中的 run
方法,如下所示:
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
User::factory(50)->create();
}
}
User::factory(50)->create();
这句代码会调用用户工厂方法,为我们生成 50 条用户数据。
用户工厂,Laravel 默认自带,文件位于 database\factories\UserFactory.php,保持默认即可,暂时不需要做修改。
然后我们修改 DatabaseSeeder.php 文件中的 run
方法,让其调用我们创建的 UserSeeder 类:
文件位置:database\seeders\DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
Model::unguard();
$this->call(UserSeeder::class);
Model::reguard();
}
}
现在,让我们回到终端中,使用以下命令,生成 Laravel 默认的用户数据表:
sail artisan migrate
接着用以下命令,填充数据
sail artisan db:seed
终端画面如下所示:
至此,数据填充完成,如果你用 Navicat 等工具连接并打开数据库中的 users 表,就可以看到 Laravel 为我们生成的 50 条用户数据,这里就不演示了。
编写 UserController 控制器的 index 方法
数据库有了数据,我们接下来编写的控制器方法才有意义,首先我们来看第一个控制器方法:
文件位置:app\Http\Controllers\UserController.php
public function index()
{
// 数据获取
// 返回数据
$data = User::select('id', 'name', 'email')->simplePaginate(10); // 简单分页
return $this->create('数据获取成功', 200, $data);
}
可以看到,我通过查询构造器,从 users 表的每条记录中选出了三个字段,并把所有的记录进行简单分页,每页展示 10 条数据。
用 Postman 进行调试,可以看到如下画面:
可以看到,之前填充的数据,被我们从数据库调出来。
index 方法还有一些其他的写法,这里仅做记录,有兴趣的同学可以自己调试以下写法:
// 获取全部可显示字段
$data = User::get();
// 获取指定字段
$data = User::select('id','name','email')->get();
// 获取指定字段并分页
$data = User::select('id','name','email')->paginate(10);
至此,查询所有数据并且分页的方法,编写完成。
6. 配置一个 404 的 HTTP 异常,并且用 JSON 格式返回(覆盖系统自带的 404 提示)
Larave 框架自带 404 提示,为什么我们还有重新写一个呢?
因为自带的 404 提示不符合 API 格式,这你让前端很难做事的,所以,我们要重写一个符合 API 格式的 404 提示,覆盖原有的提示。
操作起来也简单,两步走:
- 在 resources/views 目录下创建 errors 文件夹
- 在 resources/views/errors 目录下创建 404.blade.php 文件,并编写返回的内容
你可以手动创建相关目录和文件,也可以像我一样,在终端中使用命令来创建:
mkdir resources/views/errors && touch resources/views/errors/404.blade.php
同样,因为我在之前已经创建过,所以,此时演示的时候,提示文件夹已存在。
接下来我们开始编写 resources/views/errors 目录下的 404.blade.php 文件,很简单,以下就是文件的全部内容:
<?php
$result = [
// 返回状态码
'code' => 404,
// 返回提示信息
'msg' => '资源不存在',
// 返回数据
'data' => [],
];
echo json_encode($result);
接下来我们在 Postman 里面调试一下,填入一个不存在的路径,看看是不是我们自己编写的 404 提示(如果各位的信息显示有点乱的话,可以注意我标记红框的位置):
7. 展示单个数据 API
展示单个数据,对应的是控制器的 show 方法,通过传入的 $id 来返回对应的用户信息。
但是根据 web 开发工程师第一准则:永远不要相信用户输入的数据。
所以我们要考虑更多的东西,比如:
- 我们要求用户传入的参数是数字,但是用户扔给我们一个单词,我们该怎么办?
- 现在我们数据库里面数值的范围在 1 - 50 之内,用户给我们抛个 100 过来,超出了我们的数据范围,我们又该返回什么样的信息呢?
所以,show 方法编写如下,具体的思路请看注释部分文字:
文件位置: app\Http\Controllers\UserControllers.php
public function show($id)
{
// 获取数据
// 数据存在 返回成功信息
// 数据不存在
// 参数超出范围导致数据不存在
// 参数类型错误导致数据不存在
$data = User::select('id', 'name', 'email')->find($id);
if (isset($data)) {
return $this->create('数据获取成功', 200, $data);
} else {
if (is_numeric($id)) {
return $this->create('用户不存在', 204, []);
} else {
return $this->create('id 参数错误', 400, []);
}
}
}
Postman 调试如下(正确参数):
非数字参数:
超范围参数:
8. 新增数据 API
新增数据对应的控制器方法,是 store 方法,这部分代码我写的与原视频里面有些不同,主要区别就是在讲数据存入数据库的时候,我将密码用 md5()
函数进行加密,虽然这种方式也比较朴素,但是,起码数据库里面的数据不再是赤裸裸的 123456
了,这是什么?这就是进步啊~
文件位置: app\Http\Controllers\UserControllers.php
编码如下:
public function store(Request $request)
{
// 接收数据
$data = $request->all();
// 数据验证
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'email' => 'required|min:2|max:50|email',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
} else {
$newUser = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => md5($request->password),
]);
$newUser = User::select('id', 'name', 'email')->find($newUser['id']);
return $this->create('用户创建成功', 200, $newUser);
}
}
关于数据验证代码的解析请看原视频,或者参考本社区 《L01 Laravel 教程》的第 8 章第 4 小节。或者参考本社区 《L01 Laravel 教程》的第 6 章,此处点到为止。
以下是 Postman 调试环节,请注意我标红框的部分,都是细节哦:
9. 删除数据 API
有增加就有删除,就连后端人员的自嘲——增删改查工程师 的头两个字,也是 增 和 删 。
删除数据对应的控制器方法,是 destroy 方法,其逻辑与增加数据很相似。
文件位置: app\Http\Controllers\UserControllers.php
编码如下:
public function destroy($id)
{
// 获取数据
// 数据存在,删除
// 数据不存在
// 参数超出范围导致数据不存在
// 参数类型错误导致数据不存在
$data = User::find($id);
if (isset($data)) {
if ($data->delete()) {
return $this->create('用户删除成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('用户不存在,无法删除', 204, []);
} else {
return $this->create('id 参数错误', 400, []);
}
}
}
但是,要注意一点,在实际的生产环境中,无论我们多么想删除数据库里面的数据,事实上我们都不会删,因为我们受过专业的训练(毒打)。
那么,如何让存在数据里面的数据,看起来像是“被删除”的样子呢?
答案是增加一个 状态字段,如果一条数据的状态字段的值是 1,代表这是一条正常的记录;如果是 -1 或者其它值,代表这是一条已经被删除的记录,没有权限的人是查不到这条记录的。
由此,引申出web工程师第二准则:永远不要删除生产环境的数据。(除非你想搞破坏)
接下来是 Postman 调试(就删除我们刚刚创建的第 51 号用户好了):
此时如果我们打开数据库,发现第 51 条记录已经没有了,再次提示,这只是在本地开发环境的学习过程,在生产环境中,任何与删除有关的动作都是很危险的,一定要慎之又慎。
10. 修改数据 API
在原视频中,是没有这部分内容的,但是,出来混,要讲信用,说了增删改查工程师,就要增删改查,一个都不能少。
以下是我通过自己的理解写出来的,还是那就说话,如果有更好的写法,请在评论区 show you code
文件位置: app\Http\Controllers\UserControllers.php
编码如下:
public function update(Request $request, $id)
{
// 接收数据
// 验证数据
// 查找用户
// 如果用户不存在
// 更新并返回信息
$data = $request->all();
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
}
$user = User::find($id);
if (isset($user)) {
if ($user->update([
'name' => $request->name,
'password' => md5($request->password),
])) {
return $this->create('用户更新成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('用户不存在,无法更新', 204, []);
} else {
return $this->create('id 参数错误', 400, []);
}
}
}
代码思路请看注释文字,以下是 Postman 调试时间:
查找第一个用户的信息如下:
然后调用api,修改 1 号用户的 name 和 password 信息:
最后,再次查看,可以看到,已经修改成功:
至此,整个课程笔记已经结束。
因为之前的代码是分块编写并解释,观感并不是很好,所以在附录部分,贴上 app\Http\Controllers\UserControllers.php
的完整代码,供大家参考,以免出错。
附录
完整的app\Http\Controllers\UserControllers.php
如下:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Auth\Events\Validated;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UserController extends ApiController
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// 数据获取
// 返回数据
$data = User::select('id', 'name', 'email')->simplePaginate(10); // 简单分页
return $this->create('数据获取成功', 200, $data);
// 数据获取的其它写法举例
// 获取全部可显示字段
// $data = User::get();
// 获取指定字段
// $data = User::select('id','name','email')->get();
// 获取指定字段并分页
// $data = User::select('id','name','email')->paginate(10);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
// 接收数据
$data = $request->all();
// 数据验证
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'email' => 'required|min:2|max:50|email',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
} else {
$newUser = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => md5($request->password),
]);
$newUser = User::select('id', 'name', 'email')->find($newUser['id']);
return $this->create('用户创建成功', 200, $newUser);
}
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
// 获取数据
// 数据存在 返回成功信息
// 数据不存在
// 参数超出范围导致数据不存在
// 参数类型错误导致数据不存在
$data = User::select('id', 'name', 'email')->find($id);
if (isset($data)) {
return $this->create('数据获取成功', 200, $data);
} else {
if (is_numeric($id)) {
return $this->create('用户不存在', 204, []);
} else {
return $this->create('id 参数错误', 400, []);
}
}
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
// 接收数据
// 验证数据
// 查找用户
// 如果用户不存在
// 更新并返回信息
$data = $request->all();
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
}
$user = User::find($id);
if (isset($user)) {
if ($user->update([
'name' => $request->name,
'password' => md5($request->password),
])) {
return $this->create('用户更新成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('用户不存在,无法更新', 204, []);
} else {
return $this->create('id 参数错误', 400, []);
}
}
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
// 获取数据
// 数据存在,删除
// 数据不存在
// 参数超出范围导致数据不存在
// 参数类型错误导致数据不存在
$data = User::find($id);
if (isset($data)) {
if ($data->delete()) {
return $this->create('用户删除成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('用户不存在,无法删除', 204, []);
} else {
return $this->create('id 参数错误', 400, []);
}
}
}
}
完结,撒花,感谢阅读。