如何避免Laravel API控制器中重复的相似代码?
避免Laravel控制器重复代码的几种实用方案
针对你目前控制器中大量重复的列表查询与响应逻辑,可以通过以下几种方式简化代码:
1. 提取通用私有方法
在控制器内部封装一个通用的资源列表获取方法,将模型类和响应键作为参数传入,避免重复编写try-catch和响应结构:
use App\Models\AccountStatus; use App\Models\AccountType; use App\Models\AlertLevel; class ClientController extends Controller { /** * 获取指定模型的列表并返回统一格式响应 * @param string $modelClass 模型类全名 * @param string $responseKey 响应中的数据键名 * @return \Illuminate\Http\JsonResponse */ private function getResourceList($modelClass, $responseKey) { try { $data = $modelClass::all(); return response()->json([ 'error' => false, 'message' => 'OK', $responseKey => $data ]); } catch (\Exception $e) { return response()->json([ 'error' => true, 'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine() ], 500); } } public function getAccountStatuses() { return $this->getResourceList(AccountStatus::class, 'account_statuses'); } public function getAccountTypes() { return $this->getResourceList(AccountType::class, 'account_types'); } public function getAlertLevels() { return $this->getResourceList(AlertLevel::class, 'alert_levels'); } }
2. 通过路由参数动态处理资源
如果允许调整API路由结构,可以用单个方法处理所有资源类型,通过路由参数区分不同模型:
第一步:定义路由
在routes/api.php中添加动态路由:
Route::get('/client/resources/{type}', [ClientController::class, 'getResources']);
第二步:实现控制器方法
use App\Models\AccountStatus; use App\Models\AccountType; use App\Models\AlertLevel; use Illuminate\Http\Request; class ClientController extends Controller { // 映射资源类型标识到对应的模型和响应键 private $resourceMap = [ 'account-statuses' => [ 'model' => AccountStatus::class, 'key' => 'account_statuses' ], 'account-types' => [ 'model' => AccountType::class, 'key' => 'account_types' ], 'alert-levels' => [ 'model' => AlertLevel::class, 'key' => 'alert_levels' ] ]; public function getResources(Request $request, $type) { // 校验资源类型合法性 if (!isset($this->resourceMap[$type])) { return response()->json([ 'error' => true, 'message' => '无效的资源类型' ], 400); } $config = $this->resourceMap[$type]; try { $data = $config['model']::all(); return response()->json([ 'error' => false, 'message' => 'OK', $config['key'] => $data ]); } catch (\Exception $e) { return response()->json([ 'error' => true, 'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine() ], 500宁絮代号 origin Available永反��Letselection七八用户给冒加载控制器方法: } } }
调用API时只需传入不同的type参数,比如/client/resources/account-statuses即可获取对应数据。
3. 使用Trait复用跨控制器逻辑
如果多个控制器都有类似的列表查询需求,可以把通用逻辑抽成Trait,实现代码复用:
第一步:创建Trait
// app/Traits/ResourceListTrait.php namespace App\Traits; use Illuminate\Http\JsonResponse; trait ResourceListTrait { /** * 获取指定模型的列表并返回统一格式响应 * @param string $modelClass 模型类全名 * @param string $responseKey 响应中的数据键名 * @return JsonResponse */ public function getResourceList($modelClass, $responseKey): JsonResponse { try { $data = $modelClass::all(); return response()->json([ 'error' => false, 'message' => 'OK', $responseKey => $data ]); } catch (\Exception $e) { return response()->json([ 'error' => true, 'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine() ], 500); } } }
第二步:在控制器中使用Trait
use App\Models\AccountStatus; use App\Models\AccountType; use App\Models\AlertLevel; use App\Traits\ResourceListTrait; class ClientController extends Controller { use ResourceListTrait; public function getAccountStatuses() { return $this->getResourceList(AccountStatus::class, 'account_statuses'); } public function getAccountTypes() { return $this->getResourceList(AccountType::class, 'account_types'); } public function getAlertLevels() { return $this->getResourceList(AlertLevel::class, 'alert_levels'); } }
内容的提问来源于stack exchange,提问作者breekoy
相关产品推荐
相关产品推荐

