2.1 路由的定义方式
路由就是提供接受HTTP请求的路径,并实现与程序交互的功能。
路由的定义文件在根目录routes/web.php 中,初始项目下,可以看到 welcome 页面的定义;
Route::get('/', function () {
return view('welcome');
});
关于路由的几种基本的定义方式如下:
1. 常规定义
路由上可以定义get、post、put、delete四种基本的请求。如:
Route::get('hello', function () {
return "Hello LV!";
});
上述方法执行后,浏览器访问 localhost/hello
, 即可输入 Hello LV!
当然,也可以使用另外两种提交方法:any和match;
- any表示不管你是哪种提交方式,我智能的全部接收响应
- match表示接收你指定的提交方式,用数组作为参数传递
示例:
Route::any('hello', function () {
return "Hello LV!+Any";
});
示例:
Route::match(['get','post'],'hello',function (){
return "Hello LV!+match";
});
结果:
2. 带动态参数
路径中可以传递参数。
示例:
Route::any('hello/{name}', function ($name) {
return "Hello ,".$name;
});
结果:
当然该参数可以有很多个。
2.2 控制器的创建方式,以及与路由的绑定
MVC 模式中C 代表控制器,用于接收HTTP 请求,从而进行逻辑处理;
有两种方式可以创建控制器:
1. 使用命令创建
使用如下命令,在 Terminal
中执行,即可创建一个名为 TaskController
的控制器。
php artisan make:controller TaskController
控制器的目录在 App\Http\Controllers
目录下。
2. Controllers文件下,使用IDE 直接创建
常规的Controllers文件格式为:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
//
}
如果有的内容没有生成,则需要自己手动输入,或者在IDE里使用模板创建。
3. 简单逻辑处理实例
在上文创建的TaskController类下,可以创建几个简单的实例,如下:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
//
public function hello()
{
return 'Hello LV';
}
public function hello2($name)
{
return 'Hello,'.$name;
}
}
4 路由与控制器绑定访问
如上文创建的2个简单的方法hello和hello2,可以修改路由为如下,即可将二者绑定:
Route::get('hello', 'TaskController@hello');
Route::get('hello/{name}', 'TaskController@hello2');
上面这种方式是Laravel 6/7路由配置方式。如果是Laravel 8,则配置方式如下:
// 引入文件
use App\Http\Controllers\TaskController;
//配置路由
Route::get('hello', [TaskController::class, 'hello']);
Route::get('hello/{name}', [TaskController::class, 'hello2']);
或者将 App\Providers\RouteServiceProvider
文件中的 protected $namespace = 'App\\Http\\Controllers';
取消注释,即可,这样就不会遇到下面的错误了:
访问结果:
2.3 路由参数
1. 动态传递
关于路由参数的动态传递,在2.1 中已经讲述了。
2. 参数约束
示例:参数只能为字母,使用正则表达式约束
Route::get('hello/{name}', [TaskController::class, 'hello2'])
->where('name','[a-z]+');
Route::get('hello/{name}', 'TaskController@hello2'])
->where('name','[a-z]+');
如果有多个参数,则也可以进行约束,示例:
Route::get('hello/{name}/{id}', [TaskController::class, 'hello2'])
->where(['id'=>'[0-9]+', 'name'=>'[a-z]+']);
Route::get('hello/{name}/{id}', 'TaskController@hello2'])
->where(['id'=>'[0-9]+', 'name'=>'[a-z]+']);
如果参数输入不合法,则跳转至404页面。
3. 全局参数约束
上述操作,在某个路由后边进行约束,至对当前路由有效。
如果想对所有的路由有效,则在 app\Providers\RouteServiceProvider.php
文件下的 boot()
方法中追加以下内容即可:
public function boot()
{
Route::pattern('id', '[0-9]+');
parent::boot();
}
这时,将路由恢复至默认:
Route::get('hello/{name}/{id}', [TaskController::class, 'hello2']);
Route::get('hello/{name}/{id}', 'TaskController@hello2']);
这里的id,将服从全局约束,限制为数字。
4. 局部解除全局约束
如果想对某一处解除上述全局约束,则将路由写为如下形式:
Route::get('hello/{name}/{id}', [TaskController::class, 'hello2'])
->where(['id'=>'.*', 'name'=>'[a-z]+']);
Route::get('hello/{name}/{id}', 'TaskController@hello2'])
->where(['id'=>'.*', 'name'=>'[a-z]+']);
2.4 路由重定向
可以设置访问一个路由的URI,跳转到另一个路由的URI,具体如下:
Route::redirect('index', 'hello');
Route::redirect('index', 'hello', 301); //带状态码
如果不带状态码,则使用302跳转,即临时跳转
如果带状态码301,则执行301跳转,即永久跳转
还有一个方法,可以直接让路由跳转返回301 状态码而不用设置:
Route::permanentRedirect('index', 'task');
2.5 视图路由
在使用视图路由之前,我们先要创建一个视图(MVC)中的V 部分。
视图创建在哪儿呢?在 resources\views
目录下。
我们可以在这个目录下新建一个名为 hello.blade.php
的文件,然后写入内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>标题</title>
</head>
<body>
你好,{{$name}},你的ID是:{{$id}}
</body>
</html>
然后使用视图,加载该页面。
1. 直接使用视图路由
使用视图路由,有三个参数:1.URI(必);2.名称(必);3.参数(选);
具体方式如下:
Route::view('hello', 'hello',['name'=>'张三','id'=>'1001']);
第一个hello对应路由的访问路径,第二个hello对应创建的视图名字。
访问结果:
2. 使用助手函数
示例:
Route::get('hello', function () {
return view('hello',['name'=>'李四','id'=>'1002']);
});
执行结果:
3. 使用控制器方法(最常用)
这里的路由,使用前面的:
Route::get('hello/{name}/{id}', [TaskController::class, 'hello2']);
Route::get('hello/{name}/{id}', 'TaskController@hello2']);
然后在控制器中,修改hello2方法,为:
public function hello2($name,$id)
{
return view('hello',['name'=>$name,'id'=>$id]);
}
执行结果为:
2.5 路由命名
1. 命名
给一个制定好的路由进行命名,可以生成 URL 地址或进行重定向。如给下面的路由命名为 hello.hello2
:
Route::get('index/direct', [TaskController::class, 'hello']);
// 重命名
Route::get('hello', [TaskController::class, 'hello2'])
->name('hello.hello2');
则可以在控制器的hello方法中,使用助手函数 route()
获取路由生成的URL地址:
public function hello()
{
return route('hello.hello2');
}
打印URL结果为:
2. 生成参数URL
也可以打印带参数的URL,如:
public function hello()
{
return route('hello.hello2',['name'=>'zhangsan','id'=>'1001']);
}
结果:
如果将前文的路由修改为:
Route::get('hello/{name}', [TaskController::class, 'hello2'])
->name('hello.hello2');
则自动进行参数的匹配:
关于助手函数 route()
,默认有3个参数,第3个参数是 是否打印域名。缺省为true,如果设置为false:
public function hello()
{
return route('hello.hello2',['name'=>'zhangsan','id'=>'1001'],false);
}
结果为:
3. 重定向跳转
使用redirect()助手结合route()生成一个重定向跳转,注意不要自我死跳。示例:
controller:
public function hello()
{
return redirect()->route('hello.hello2',['name'=>'zhangsan','id'=>'1001']);
}
route:
Route::get('hello/{name}/{id}', [TaskController::class, 'hello2'])
->name('hello.hello2');
执行完成后,跳转至 [http://127.0.0.1:8000/hello/zhangsan/1001](http://127.0.0.1:8000/hello/zhangsan/1001)
,如图:
2.6 路由分组
1. 普通的加前缀
使用路由里的 prefix('前缀名')
即可实现加前缀。
示例:
//这是前面的,不动
Route::get('hello/{name}/{id}', [TaskController::class, 'hello2'])
->name('hello.hello2');
//加前缀
Route::prefix('api')->get('test', function () {
return 'test';
});
Route::prefix('api')->get('direct', [TaskController::class, 'hello']);
然后在浏览器中访问,需要加前缀 api
才能访问:
2. 使用分组
下面这个例子,是在路由前面加上前缀api
Route::group(['prefix' => 'api'], function () {
Route::get('index/{id}', function ($id) {
return 'index' . $id;
});
Route::get('task/{id}', function ($id) {
return 'task' . $id;
});
});
当然,我们推荐下面这种方式:
Route::prefix('api')->group( function () {
Route::get('index/{id}', function ($id) {
return 'index' . $id;
});
Route::get('task/{id}', function ($id) {
return 'task' . $id;
});
});
3. 使用子域名
也有两种方法,如下:
//方式一
Route::domain('127.0.0.1')->group( function () {
Route::get('index/{id}', function ($id) {
return 'index' . $id;
});
Route::get('task/{id}', function ($id) {
return 'task' . $id;
});
});
//方式二
Route::group(['domain' => '127.0.0.1'], function () {
Route::get('index/{id}', function ($id) {
return 'index' . $id;
});
Route::get('task/{id}', function ($id) {
return 'task' . $id;
});
});
4. 使用中间件
也有两种方法,如下:
//方式一
Route::middleware('中间件名称')->group( function () {
Route::get('index/{id}', function ($id) {
return 'index' . $id;
});
Route::get('task/{id}', function ($id) {
return 'task' . $id;
});
});
//方式二
Route::group(['middleware' => '中间件名称'], function () {
Route::get('index/{id}', function ($id) {
return 'index' . $id;
});
Route::get('task/{id}', function ($id) {
return 'task' . $id;
});
});
5. 命名空间
默认的控制类的命名空间是在 App\Http\Controllers
目录下。
如果在该目录下新建一个名为 Admin
的空间,并在该空间下新建一个名为 ManageComtroller.php
,那么路由是无法找到 Admin
下的 ManageComtroller
控制类的。
那么可以用如下方式访问:
Route::namespace('Admin')->group(function () {
Route::get('admin/index', [ManageController::class, 'index']);
});
结果:
但是,在Laravel8中,这些控制类是需要在Route中包含进来的,所以该方式也就没多少用处。
6. 嵌套方式
很少用,不赘述。
如果有用到,再回来补充。
2.7 单行为控制器
顾名思义,定义一个只执行一个方法的控制器。固定使用 __invoke()
方法。
可以手动创建,也可以命令创建:
php artisan make:controller OneController --invokable
创建完成后,生成一个名为OneController的控制器,默认内容如下:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class OneController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
//
}
}
在 __invoke
方法中写入内容:
public function __invoke()
{
//
return '单行为控制器';
}
使用下面的路由即可访问,不需要加方法名。
Route::get('one', 'OneController@__invoke');
结果:
2.8 回退路由
如果我们跳转到了一个不存在路由时,会产生404 错误,体验不佳。
主要有两种解决方法:1. 跳转至指定页面;2. 跳转至404页面。
Route::fallback(function () {
//跳转至指定页面
return redirect('/');
//跳转至404页面
return view('404');
});
注意:由于执行顺序问题,必须把回退路由放在所有路由的最底部。
2.9 当前路由
我们可以通过使用::current()系列方法,来获取当前路由的访问信息,用于调试。
示例:
Route::get('index', function () {
//当前路由信息
dump(Route::current());
//返回当前路由的名称
return Route::currentRouteName();
//返回当前路由指向的方法
return Route::currentRouteAction();
})->name('localhost.index');
2.10 跳转重定向
重定向使用助手函数redirect(),快捷方式是这样的:
Route::get('index', function () {
//跳转至首页
return redirect('/');
//return redirect('task'); //跳转到task
//return redirect('task/url'); //跳转到task/url
});
当前,快捷方式的完整写法是这样的:
Route::get('index', function () {
//跳转至首页
return redirect()->to('/'); //跳到首页
//return redirect()->to('task'); //跳转到task
//return redirect()->to('task/url'); //跳转到task/url
});
另外,redirect()助手有一个对应的facade 模式对象,也可以使用这种方法:
Route::get('index', function () {
//跳转至首页
return Redirect::to('/'); //facade 模式,但需要use 引入
});
另外,使用redirect()的route()方法,可以跳转到指定的命名路由URI:
Route::get('one', 'OneController')->name('index.one');
Route::get('index', function () {
//跳转至one
return redirect()->route('index.one');
});
使用redirect()的back()方法,可以重定向到上一个页面中:
Route::get('back', function () {
//后退
return redirect()->back();
//快捷方式
//return back();
});
使用redirect()的action()方法,可以直接重定向到控制器方法:
Route::get('hello2', 'TaskController@hello2');
Route::get('index', function () {
//return redirect()->action('TaskController@hello2'); //需注册路由
return redirect()->action('TaskController@hello2', ['name' => 'zhangsan', 'id' => 10]);
});
使用redirect()的away()方法,跳转到外部链接:
Route::get('index', function () {
return redirect()->away('http://www.baidu.com');
});
以上。