【Laravel】2. 路由模块基础知识

215 阅读3分钟

作者:拾年之璐   公众号:知行研究院

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!

image-20210104175000556

当然,也可以使用另外两种提交方法:any和match;

  • any表示不管你是哪种提交方式,我智能的全部接收响应

  • match表示接收你指定的提交方式,用数组作为参数传递

示例:

Route::any('hello', function () {
    return "Hello LV!+Any";
});

示例:

Route::match(['get','post'],'hello',function (){
    return "Hello LV!+match";
});

结果:

image-20210104175339701

2. 带动态参数

路径中可以传递参数。

示例:

Route::any('hello/{name}', function ($name) {
    return "Hello ,".$name;
});

结果:

image-20210104175508543

当然该参数可以有很多个。

2.2 控制器的创建方式,以及与路由的绑定

MVC 模式中C 代表控制器,用于接收HTTP 请求,从而进行逻辑处理;

有两种方式可以创建控制器:

1. 使用命令创建

使用如下命令,在 Terminal 中执行,即可创建一个名为 TaskController 的控制器。

php artisan make:controller TaskController

控制器的目录在 App\Http\Controllers 目录下。

image-20210104180607970

image-20210104180632972

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'; 取消注释,即可,这样就不会遇到下面的错误了:

image-20210105143820448

访问结果:

image-20210104182619129

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对应创建的视图名字。

访问结果:

image-20210104195251857

2. 使用助手函数

示例:

Route::get('hello', function () {
    return view('hello',['name'=>'李四','id'=>'1002']);
});

执行结果:

image-20210104195535241

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]);
    }

执行结果为:

image-20210104195925407

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结果为:

image-20210104203522624

2. 生成参数URL

也可以打印带参数的URL,如:

    public function hello()
    {
        return route('hello.hello2',['name'=>'zhangsan','id'=>'1001']);
    }

结果:

image-20210104203845746

如果将前文的路由修改为:

Route::get('hello/{name}', [TaskController::class, 'hello2'])
    ->name('hello.hello2');

则自动进行参数的匹配:

image-20210104203859334

关于助手函数 route() ,默认有3个参数,第3个参数是 是否打印域名。缺省为true,如果设置为false:

    public function hello()
    {
        return route('hello.hello2',['name'=>'zhangsan','id'=>'1001'],false);
    }

结果为:

image-20210104204053216

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 ,如图:

image-20210104204554922

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 才能访问:

image-20210104205253481

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 控制类的。

image-20210104210623417

那么可以用如下方式访问:

Route::namespace('Admin')->group(function () {
    Route::get('admin/index', [ManageController::class, 'index']);
});

结果:

image-20210104211422713

但是,在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');

结果:

image-20210105144452926

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');
});

以上。