题目
在Laravel中如何实现一个支持分页、搜索和排序的用户列表API?
信息
- 类型:问答
- 难度:⭐⭐
考点
Eloquent查询构建,请求参数验证,分页器处理,API资源转换
快速回答
实现步骤:
- 通过请求对象获取查询参数(页码、搜索关键词、排序字段)
- 使用Eloquent的
when()条件查询处理搜索和排序 - 调用
paginate()方法实现分页 - 使用API资源类格式化响应结构
关键代码:
$users = User::query()
->when($request->search, fn($q) => $q->where('name','like',"%{$request->search}%"))
->orderBy($request->sort_by ?? 'id', $request->sort_dir ?? 'asc')
->paginate($request->per_page ?? 15);
return UserResource::collection($users);
## 解析
该功能考察Laravel核心组件的综合应用能力,下面分步骤说明实现细节:
1. 请求参数处理与验证
// 在控制器方法中注入请求对象
public function index(Request $request)
{
// 验证参数(Laravel内置验证器)
$validated = $request->validate([
'page' => 'sometimes|integer|min:1',
'per_page' => 'sometimes|integer|min:1|max:100',
'search' => 'sometimes|string|max:50',
'sort_by' => 'sometimes|in:name,email,created_at',
'sort_dir' => 'sometimes|in:asc,desc'
]);
// ...后续逻辑
}原理说明:使用Laravel的FormRequest或直接validate()方法确保输入安全,防止SQL注入和无效参数。
2. 构建动态查询
$query = User::query();
// 搜索处理(多字段示例)
if ($request->has('search')) {
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%$search%")
->orWhere('email', 'like', "%$search%");
});
}
// 排序处理(防止注入)
$sortBy = in_array($request->sort_by, ['name','email'])
? $request->sort_by
: 'created_at';
$sortDir = $request->sort_dir === 'desc' ? 'desc' : 'asc';
$query->orderBy($sortBy, $sortDir);最佳实践:
- 使用
when()方法使条件查询更流畅 - 对排序字段进行白名单校验
- 搜索使用闭包避免orWhere链断裂
3. 分页与响应格式化
// 分页处理
$perPage = $request->per_page ?? config('app.default_per_page');
$users = $query->paginate($perPage);
// 使用API资源类(UserResource.php)
class UserResource extends JsonResource {
public function toArray($request) {
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at->toIso8601String()
];
}
}
// 控制器返回
return UserResource::collection($users);响应结构示例:
{
"data": [
{"id":1, "name":"John", ...}
],
"meta": {
"current_page": 1,
"per_page": 15,
"total": 100
}
}4. 常见错误与优化
- N+1查询问题:在查询中使用
->with('posts')预加载关联数据 - 性能问题:对搜索字段添加数据库索引,大数据量时考虑Elasticsearch
- 安全漏洞:永远不要直接将请求参数传入
orderBy(),必须校验字段合法性 - 分页参数:限制每页最大数量防止DoS攻击
5. 扩展知识
- API资源集合:可创建
UserResourceCollection自定义分页元数据结构 - 更复杂的搜索:使用Laravel Scout实现全文搜索
- 缓存策略:对高频查询添加Redis缓存:
->remember(now()->addMinutes(30)) - 测试技巧:使用Laravel HTTP测试模拟分页请求:
$response->assertJsonStructure(['data','meta'])