Laravel 11 路由命名与分组

随着应用规模的增长,路由数量也会不断增加。Laravel 提供了路由命名和分组机制,让路由管理更加高效、可维护。 本章将深入讲解如何为路由命名,以及如何利用分组简化重复配置。

🏷️ 路由命名

为路由指定一个名称,可以在生成 URL 或重定向时通过名称引用路由,避免硬编码 URI 带来的维护成本。

1. 定义命名路由

使用 name 方法为路由链式添加名称:

Route::get('/user/profile', function () {
    // ...
})->name('profile');

也可以在定义资源路由时自动生成名称(稍后会介绍)。

2. 使用命名路由生成 URL

通过 route 辅助函数根据路由名称生成 URL:

$url = route('profile'); // 生成 /user/profile

// 如果路由有参数
Route::get('/user/{id}/profile', function ($id) {
    // ...
})->name('profile.show');

$url = route('profile.show', ['id' => 1]); // /user/1/profile

// 传递额外查询参数
$url = route('profile.show', ['id' => 1, 'page' => 2]); // /user/1/profile?page=2
3. 在 Blade 模板中使用

Blade 中可以直接使用 route 辅助函数:

<a href="{{ route('profile.show', ['id' => $user->id]) }}">查看资料</a>
4. 重定向到命名路由

控制器或中间件中可以使用 redirect()->route()

return redirect()->route('profile');
💡 优势: 当路由 URI 需要变更时,只需修改路由定义,所有使用 route() 生成的链接会自动更新,无需逐个文件查找替换。
5. 检查当前路由是否命名

在中间件或视图中,可以通过 Route::currentRouteName() 获取当前路由名称:

$name = Route::currentRouteName(); // 返回字符串,如 'profile.show'

// 判断是否匹配
if (Route::currentRouteName() == 'profile.show') {
    // ...
}

📦 路由分组

路由分组允许共享路由属性(如中间件、前缀、命名空间、域名等),避免为每个路由单独设置。分组通过 Route::group 方法或链式语法实现。

1. 中间件分组

为一组路由分配相同的中间件:

Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        return '仪表盘';
    });
    Route::get('/settings', function () {
        return '设置页面';
    });
});
2. 路径前缀分组

为一组路由统一添加 URI 前缀:

Route::prefix('admin')->group(function () {
    Route::get('/users', function () {
        return '管理用户列表';
    });
    Route::get('/posts', function () {
        return '管理文章列表';
    });
});
// 实际路由:/admin/users, /admin/posts
3. 子域名路由

将路由限定在特定子域名下:

Route::domain('api.example.com')->group(function () {
    Route::get('/status', function () {
        return 'API 状态';
    });
});
4. 控制器命名空间分组

在 Laravel 11 中,路由文件默认不包含控制器命名空间前缀,但分组仍可指定命名空间(通常用于模块化开发):

Route::namespace('App\Http\Controllers\Admin')->group(function () {
    // 此组内的控制器引用将相对于 "App\Http\Controllers\Admin"
    Route::get('/users', 'UserController@index');
});

注意:Laravel 11 更推荐使用显式导入控制器类的方式,但命名空间分组依然可用。

5. 路由名称前缀分组

为分组内的路由名称添加统一前缀:

Route::name('admin.')->prefix('admin')->group(function () {
    Route::get('/users', function () {
        // ...
    })->name('users'); // 完整名称:admin.users

    Route::get('/posts', function () {
        // ...
    })->name('posts'); // admin.posts
});
6. 组合多个属性

可以将多个分组属性链式组合:

Route::prefix('admin')
    ->middleware(['auth', 'admin'])
    ->name('admin.')
    ->group(function () {
        Route::get('/dashboard', [AdminController::class, 'dashboard'])->name('dashboard');
        // 完整路由:/admin/dashboard,名称:admin.dashboard,中间件:auth,admin
    });

🔄 分组嵌套

分组可以嵌套使用,属性会合并:

Route::prefix('api')->middleware('api')->group(function () {
    Route::prefix('v1')->group(function () {
        Route::get('/users', function () {
            return 'API v1 用户列表';
        });
    });
});
// 最终路由:/api/v1/users,中间件:api

🗂️ 资源路由的命名

使用 Route::resource 创建的资源路由会自动生成一组命名路由,遵循统一的命名规范:

Route::resource('photos', PhotoController::class);

生成的命名路由如下:

动作 路由名称 URI
indexphotos.index/photos
createphotos.create/photos/create
storephotos.store/photos
showphotos.show/photos/{photo}
editphotos.edit/photos/{photo}/edit
updatephotos.update/photos/{photo}
destroyphotos.destroy/photos/{photo}

可以通过 names 数组自定义资源路由的名称:

Route::resource('photos', PhotoController::class)->names([
    'create' => 'photos.build',
    'show' => 'photos.view',
]);
部分资源路由命名

如果只保留部分操作,生成的名称也只包含相应动作:

Route::resource('photos', PhotoController::class)->only(['index', 'show']);
// 名称:photos.index, photos.show

🔍 查看所有命名路由

使用 Artisan 命令 route:list 可以查看所有已注册路由及其名称:

php artisan route:list

输出表格中包含 Name 列,显示每个路由的名称。如果名称列为空,表示该路由未命名。

📝 路由命名的最佳实践

  • 命名规范:通常使用点号分隔的层级结构,如 admin.users.index,与视图或控制器命名保持一致。
  • 避免命名冲突:不同功能模块尽量使用独特的前缀(如 admin.api.)。
  • 在模型关联中使用:通过 route('posts.show', $post) 可以直接传递模型实例,Laravel 会自动解析其路由键。

🎯 实战示例:用户管理模块

以下是一个用户管理模块的路由定义,综合运用了命名、分组和资源路由:

Route::prefix('admin')
    ->middleware(['auth', 'admin'])
    ->name('admin.')
    ->group(function () {

        // 仪表盘
        Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');

        // 用户资源管理
        Route::resource('users', UserController::class)->except(['show']);

        // 自定义用户操作
        Route::post('/users/{user}/toggle-status', [UserController::class, 'toggleStatus'])
            ->name('users.toggle-status');
    });

生成的典型路由:

  • admin.dashboard/admin/dashboard
  • admin.users.index/admin/users
  • admin.users.create/admin/users/create
  • admin.users.store/admin/users (POST)
  • admin.users.edit/admin/users/{user}/edit
  • admin.users.update/admin/users/{user} (PUT/PATCH)
  • admin.users.destroy/admin/users/{user} (DELETE)
  • admin.users.toggle-status/admin/users/{user}/toggle-status (POST)
⚠️ 注意: 在 Laravel 11 中,路由文件的控制器命名空间不再是默认添加的,因此使用字符串方式引用控制器(如 'UserController@index')时需要在 RouteServiceProvider 中设置命名空间,或者推荐使用 ::class 引用。

❓ 常见问题

路由命名是现代开发的最佳实践。它使代码更健壮,当 URL 结构变化时只需修改路由定义,无需改动业务代码。

理论上没有限制,但过度嵌套会降低可读性,建议最多 2-3 层。

可以在资源路由定义后单独定义,并确保命名不与资源冲突,或者使用 names 方法自定义。

📌 小结

路由命名和分组是 Laravel 组织路由的强大工具。命名让路由引用变得简单且可维护,分组则通过共享属性消除了重复代码。 熟练掌握这些技巧,能够让你在构建大型应用时保持路由文件的整洁和可读性。 下一章我们将深入控制器,学习如何将业务逻辑更好地组织起来。