什么是路由?
路由不是你家里的路由器,是URL与函数直接的关系映射。
参考手册 路由
所有 Laravel 路由都定义在路由文件中,这些文件位于
routes
目录下。
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
这些路由被分配给
web
中间件组, 该组提供会话状态和 CSRF 保护等功能。
基本路由
最基本的 Laravel 路由接受一个 URI 和一个闭包,它提供了一种非常简单和有表现力的方法来定义路由和行为,而不需要复杂的路由配置文件:
use Illuminate\Support\Facades\Route;
Route::get('/greeting', function () {
return 'Hello World';
});
Route::get('/user', [UserController::class, 'index']);
Route::redirect('/here', '/there');
默认情况, Route::redirect
返回的状态码是 302
。 但你可以使用第三个可选参数自定义状态码:
Route::redirect('/here', '/there', 301);
如果你的路由只需要返回一个 view,你可以使用 Route::view
方法。 像 redirect
方法一样, 此方法提供了一个简单的快捷方式,因此您不必定义完整的路由或控制器。 该 view
方法接受 URI 作为其第一个参数,并接受视图名称作为其第二个参数。另外,您可以提供一个数据数组作为可选的第三个参数传递给视图:
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
有的时候你可能需要注册一个可响应多个 HTTP 请求的路由,这时你可以使用 match 方法,也可以使用 any 方法注册一个实现响应所有 HTTP 请求的路由:
Route::match(['get', 'post'], '/', function () {
//支持两种方法
});
Route::any('foo', function () {
//可以接收所有的方法
});
必填参数
有时您将需要捕获路由内的 URI 段。例如,您可能需要从 URL 中捕获用户的 ID。您可以通过定义路由参数来做到这一点:
Route::get('/user/{id}', function ($id) {
return 'User '.$id;
});
也可以根据您的需要在路由中定义多个参数:
Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
有时,你可能需要指定一个路由参数,但你希望这个参数是可选的。你可以在参数后面加上 ?
标记来实现,但前提是要确保路由的相应变量有默认值:
Route::get('/user/{name?}', function ($name = null) {
return $name;
});
Route::get('/user/{name?}', function ($name = 'John') {
return $name;
});
你可以使用路由实例上的 where
方法约束路由参数的格式。where
方法接受参数名称和定义参数应如何约束的正则表达式:
Route::get('/user/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+');
Route::get('/user/{id}', function ($id) {
//
})->where('id', '[0-9]+');
Route::get('/user/{id}/{name}', function ($id, $name) {
//
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
路由命名可以方便地为指定路由生成 URL 或者重定向。通过在路由定义上链式调用 name
方法可以指定路由名称:
Route::get('/user/profile', function () {
//
})->name('profile');
注意:路由命名必须是唯一的
一旦为路由指定了名称,你可以在生成 url 或者通过 Laravel 的 route
和 redirect
辅助函数重定向时使用路由的名字:
// 生成链接...
$url = route('profile');
// 生成重定向...
return redirect()->route('profile');
如果有定义参数的命名路由,可以把参数作为 route
函数的第二个参数传入,指定的参数将会自动插入到 URL 中对应的位置:
Route::get('/user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1]);
如果在数组中传递其他参数,这些键或值对将自动添加到生成的 URL 查询字符串中:
Route::get('/user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// /user/1/profile?photos=yes
路由组允许你共享路由属性,例如中间件,这样不需要在每个单独的路由上定义那些属性。
嵌套组会尝试智能的 “合并” 他们的父组的属性。中间件和 “where” 条件会被合并,而名称和前缀会被追加。URI 前缀中的名称空间分隔符和斜杠会在适当的地方自动添加。
想把中间件分配给组内所有的路由,你可以在定义组之前使用 middleware
方法。中间件将按照它们在数组中列出的顺序执行:
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second middleware...
});
Route::get('/user/profile', function () {
// Uses first & second middleware...
});
});
路由组也可以用来处理子域路由。子域可以像路由 uri 一样被分配路由参数,允许您捕获子域的一部分以便在路由或控制器中使用。 子域可以在定义组之前调用 domain
方法来指定:
Route::domain('{account}.example.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
prefix
方法可以用给定的 URI 为组中的每个路由做前缀。例如,你可能想要在组内的所有路由 uri 前面加上 admin
前缀:
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
// Matches The "/admin/users" URL
});
});
name
方法可以用给定字符串作为组中的每个路由名的前缀。 例如,你可能想要用 admin
作为所有分组路由的前缀。因为给定字符串的前缀与指定的路由名完全一致,所以我们一定要提供末尾 .
字符在前缀中:
Route::name('admin.')->group(function () {
Route::get('/users', function () {
// Route assigned name "admin.users"...
})->name('users');
});
将应用程序部署到生产环境时,应该利用 Laravel 的路由缓存。使用路由缓存将大大减少注册所有应用程序路由所花费的时间。要生成路由缓存,请执行 route:cache
Artisan 命令:
php artisan route:cache
运行此命令后,缓存的路由文件将在每个请求中加载。请记住,如果添加任何新路由,则将需要生成新的路由缓存。因此,route:cache
命令最好在生产环境运行。
您可以使用以下 route:clear
命令清除路由缓存:
php artisan route:clear
Route::get('/', function () {
return view('welcome');
});
Route::get('/h', function () {
return 'hello word';
});
Route::get('/user', function () {
return 'user';
});
Route::get('/user/create', [UserController::class,'create']);
Route::post('/user',[UserController::class,'store'] )->name('create');
Route::get('/users', [UserController::class,'index']);
Route::get('/users/{id}', [UserController::class,'show']);
//Route::resource('/goods',GoodsController::class)->only(['index','show']);
Route::resource('/goods',GoodsController::class)->except(['create','show']);
//apiResource
Route::redirect('/u','user',301);
Route::match(['get','post'],'/getpost',function (){
dd('getpost');
});
Route::any('/any',function (){
dd('any');
});
//Route::get('/member/{id?}',function ($id){
// return $id;
//});
//Route::get('/member/{id}/courses/{course}',function ($id,$course){
// dd($id,$course);
//})->where('id','[A-Za-z0-9]+');
Route::get('/member/{id}/courses/{course}',function ($id,$course){
dd($id,$course);
})->where(['id'=>'[0-9]+','course'=>'[A-Za-z0-9]+']);
Route::get('/member/{id}',function ($id){
dd(route('member.show',['id'=>$id]));
})->name('member.show');
Route::get('/member',function (){
return redirect()->route('member.show',['id'=>1]);
});
Route::post('upload',UploadController::class);
Route::domain('api.lala.test')->name('admin.')->prefix('admin')->group(function (){
Route::get('/user', function () {
dd('admin/user');
})->name('users');
Route::get('/goods', function () {
dd('admin/goods');
})->name('goods');
});
//路由缓存
//php artisan route:cache
//清除缓存
//php artisan route:clear
//
// php artisan route:list |grep list
// php artisan make:controller GoodsController --resource
// php artisan make:controller Home/UserController
//php artisan make:controller PhotoController --resource --model=Photo
参考手册 控制器
我们要使用“控制器”的类来管理我们业务逻辑代码,而不是将所有请求处理逻辑定义为路由文件中的闭包。控制器可以将相关的请求处理逻辑分组到一个类中。例如,一个
UserController
类可能会处理所有与用户相关的传入请求,包括显示、创建、更新和删除用户。默认情况下,控制器存储在app/Http/Controllers
目录中。
Laravel artisan 给我们提供了创建 Controller
的命令,你只需执行下面代码
php artisan make:controller UserController
他将会在 app/Http/Controllers
这个目录下生成UserController
你可以在路由文件中添加上
Route::get('profile', [UserController::class, 'show']);
接着可以在UserController
中添加show方法,测试路由的和控制的连接。
通常在一个项目中,我们有前台和后台,在使用
php artisan make:controller
的时候你可以,在控制器的前面添加目录名称来区分前后台,例:php artisan make:controller Admin/UserController
这样创建的控制器将会在app/Http/Controller/Admin
目录下。
如果说我们的控制器对应到每个模型上面,每个资源都有相同的操作,你会有 UserController
或者GoodController
,每个控制器中都会有对应的方法,获取列表、创建、删除、修改、查看、编辑页面、添加页面等。我们需要在路由中为每个控制的每个方法去创建对应的路由,并且在控制器创建不同的方法。我们需要统一这个方法名和路由创建的方式,例如:不可能在 UserController
中获取列表我们叫list
而在 GoodController
中我们叫 index
,在团队开发中这回产生歧义,我们可以使用下面命令快速创建一个控制器。
php artisan make:controller UserController --resource
这个命令将会生成一个控制器 app/Http/Controllers/UserController.php
。其中包括每个可用资源操作的方法。接下来,你可以给控制器注册一个资源路由:
use App\Http\Controllers\UserController;
Route::resource('users', UserController::class);
这个单一的路由声明创建了多个路由来处理资源上的各种行为。生成的控制器为每个行为保留了方法, 而且你可以通过运行 Artisan 命令 route:list
来快速了解你的应用程序。
请求方式 | URI | Action | 路由名称 |
---|---|---|---|
GET | /users |
index | users.index |
GET | /users/create |
create | users.create |
POST | /users |
store | users.store |
GET | /users/{users} |
show | users.show |
GET | /users/{users}/edit |
edit | users.edit |
PUT/PATCH | /users/{users} |
update | users.update |
DELETE | /users/{users} |
destroy | users.destroy |
如果你使用了路由模型的绑定 路由模型绑定 并且想在资源控制器的方法中使用类型提示,你可以在生成控制器的时候使用 --model
选项:
php artisan make:controller PhotoController --resource --model=Photo
当声明资源路由时,你可以指定控制器处理的部分行为,而不是所有默认的行为:
use App\Http\Controllers\PhotoController;
Route::resource('photos', PhotoController::class)->only([
'index', 'show'
]);
Route::resource('photos', PhotoController::class)->except([
'create', 'store', 'update', 'destroy'
]);
当声明用于 APIs 的资源路由时,通常需要排除显示 HTML 模板的路由。例如 create
and edit
。为了方便起见 apiResource
方法自动排除这两个路由:
use App\Http\Controllers\PhotoController;
Route::apiResource('photos', PhotoController::class);
你也可以传递一个数组给 apiResources
方法来同时注册多个 API 资源控制器:
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\PostController;
Route::apiResources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);
要快速生成不包含 create
或 edit
方法的用于开发接口的资源控制器,请在执行 make:controller
命令时使用 --api
参数:
php artisan make:controller PhotoController --api
默认情况下,所有的资源控制器行为都有一个路由名称。你可以传入 names
数组来覆盖这些名称:
use App\Http\Controllers\PhotoController;
Route::resource('photos', PhotoController::class)->names([
'create' => 'photos.build'
]);
默认情况下,Route::resource
会根据资源名称的「单数」形式创建资源路由的路由参数。你可以在选项数组中传入 parameters
参数来轻松地覆盖每个资源。parameters
数组应该是资源名称和参数名称的关联数组:
use App\Http\Controllers\AdminUserController;
Route::resource('users', AdminUserController::class)->parameters([
'users' => 'admin_user'
]);
上面的示例将会为资源的 show
路由生成以下的 URL:
/users/{admin_user}
如果你需要增加额外的路由到默认的资源路由之中,你需要在 Route::resource
前定义它们;否则,由 resource
方法定义的路由可能会无意间优先于你定义的路由:
use App\Http\Controller\PhotoController;
Route::get('/photos/popular', [PhotoController::class, 'popular']);
Route::resource('photos', PhotoController::class);