路由使用

基本路由定义

参考内容 | laravel 5.7

  • (前缀) prefix/uri 路由前缀 <=>
  • (别名) 路由别名 <=> <=>
  • (中间件) <=>
  • (命名空间) <=>
  • (控制器定义) 参看一下示例
prefix 前缀
# prefix 用于添加路由前缀 
# 请求路径地址  /pr/index
# 示例一
Route::get( '/index', ['prefix'=>'pr',function(){
    return "get";
}] );

# 示例二
# prefix( string $prefix)
Route::get('/index',function(){
    return "get";
})->prefix('pr');
as 别名
# as 别名 as()函数支持静态 name()支持静态和实例访问
# 示例一
Route::post('index',['as'=>'foo.index','uses'=>'Index\\IndexController@index']);

# 示例二
# name(string $value)
Route::post('index','Index\\IndexController@index')->name('foo.index');
# 访问形式 $url = route('foo.index');
middleware 中间件
  • 更多中间件使用 参看中间件文档
# middleware 中间件 当前路由需加载的中间件
# 示例一
Route::get('index', ['middleware'=>'api',function(){
    return "get";
}]);
Route::get('index', ['middleware'=>['api','token'],function(){
    return "get";
}]);

# middleware(array|string|null $middleware)
# 示例二
# 中间件
Route::get('index', function(){
    return "get";
})->middleware( CheckToken::class );

# 示例三
# 一个或多个中间件
Route::get('index', function(){
    return "get";
})->middleware('api','auth');
Route::get('index', function(){
    return "get";
})->middleware(['api','auth']);

# 示例四
# 中间件参数 在定义路由时通过 : 分隔中间件名和参数名来指定,多个中间件参数可以通过逗号分隔
Route::get('index', ['uses'=>'IndexController@index'])->middleware('throttle:60,1');
namespace 命名空间
# 命名空间在 系统的 App\Http\Controller 后续加
# namespace App\Http\Controller\Index
Route::post('/index',[
    'namespace' => 'Index',
    'uses' => 'IndexController@index'
]);

# namespace(string $value); 添加后续空间名称
Route::namespace('Index')->post('/index',[
    'uses' => 'IndexController@index'
]);

Route::namespace('Index')->post('/index', 'Index\\IndexController@index');
Route 支持方法
# Route::get( $uri, $action ); GET请求(包含 get、head 两种请求类别)
# get:获取指定的页面信息,并返回实体主体
# head:用于获取报头(类似于GET;不会返回页面具体内容)
@method static \Illuminate\Routing\Route 
get(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::get('/', function(){
    return view('welcome');
});

# 示例二  namespace App\Http\Controllers\Index
Route::get('/', 'Index\\IndexController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::post( $uri, $action ); POST请求
# post:新增数据
@method static \Illuminate\Routing\Route 
post(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::post('/', function(){
    return "post";
});

# 示例二  namespace App\Http\Controllers\Index
Route::post('/', 'Index\\IndexController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::put( $uri, $action ); PUT请求
# put:更新数据
@method static \Illuminate\Routing\Route 
put(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::put('/', function(){
    return "put";
});

# 示例二  namespace App\Http\Controllers
Route::put('/', 'IndexController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::delete( $uri, $action ); DEFAULT 请求
# delete:删除服务器指定页面
@method static \Illuminate\Routing\Route 
delete(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::delete('/', function(){
    return "delete";
});

# 示例二  namespace App\Http\Controllers
Route::delete('/', 'IndexController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::patch( $uri, $action);  PATCH请求
# patch:更新部分数据(例如更新某个字段的值)
@method static \Illuminate\Routing\Route 
patch(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::patch('/', function(){
    return "patch";
});

# 示例二  namespace App\Http\Controllers
Route::patch('/', 'IndexController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::options( $uri, $action);  OPTIONS请求
# 获取服务器支持的HTTP请求方法、用来检查服务器的性能;
@method static \Illuminate\Routing\Route 
options(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::options('/', function(){
    return "options";
});

# 示例二  namespace App\Http\Controllers
Route::options('/', 'IndexController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::any( $uri, $action ); 注册所有的http动作
@method static \Illuminate\Routing\Route 
any(string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::any('/', function(){
    return "any";
});

# 示例二  namespace App\Http\Controllers
Route::any('/', 'IndexController@index');


# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <<

# Route::match( $methods, $uri, $action ); 允许指定动作通过
@method static \Illuminate\Routing\Route 
match(array|string $methods, string $uri, \Closure|array|string|null $action = null)

# 示例一
Route::match(['get','post','delete'],'/', function(){
    return "match";
});

# 示例二  namespace App\Http\Controllers
Route::match(['get','post','delete'],'/', 'IndexController@index');
Route 连贯操作
# prefix 路由前缀
@method static \Illuminate\Routing\RouteRegistrar 
prefix(string  $prefix)
# 中间件
@method static \Illuminate\Routing\RouteRegistrar 
middleware(array|string|null $middleware)
# 路由别名
@method static \Illuminate\Routing\RouteRegistrar 
as(string $value)
@method static \Illuminate\Routing\RouteRegistrar 
name(string $value)
# 命名空间
@method static \Illuminate\Routing\RouteRegistrar 
namespace(string $value)
路由群组
  • 路由群组 参数
  • 组前缀 使用和基本路由使用一致 参看前处
  • 子域名 <=>
  • 组命名空间 使用和基本路由使用一致 参看前处
  • 组中间件 使用和基本路由使用一致 参看前处
@method static \Illuminate\Routing\Router|\Illuminate\Routing\RouteRegistrar 
group(array|\Closure|string $attributes, \Closure|string $routes)
# 示例
Route::group(['namespace'=>'Admin','prefix'=>'admin','middleware'=>'throttle:60,1'], function($router){
    $router->get('index','IndexController@index')->name('foo.index');
});
# 示例
# 使用该子域名路由参数:需要改子域名存在的情况下
Route::group(['namespace'=>'Admin','prefix'=>'admin','domain'=>'{account}.bymyside.dv'],function ($route){
    $route->get('p','PhotoController@index')->name('p.index');
    //> 子域名
    $route->get('domain', function($account){
        echo $account;
    });
});
路由重定向
# uri 原路由
# destination 重定向之后路由
# status 301 重定向标识 http响应码
@method static \Illuminate\Routing\Route 
redirect(string $uri, string $destination, int $status = 301)

# 示例
Route::redirect( '/here', 'there', 301 );
路由视图
# uri 路由
# view 视图名称
# data 视图数据
@method static \Illuminate\Routing\Route 
view(string $uri, string $view, array $data = [])

# 示例
Route::view('/index', 'welcome');
Route::view('/index', 'welcome', ['name' => 'ss']);
路由参数
路由使用_第1张图片
# 路由参数使用{}(花括号)包裹,该路由在执行时会一一对应传递到闭包函数或控制器中
# 注意:路由参数不能包含 - (中划线),使用 _ (下划线)代替
Route::get('photos/{user_id}','User\\UserController@index');

# >> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - << 
# 可选参数(路由参数)
# 可选参数 使用花括号({})包裹;在参数后面添加一个?(问号):表示该参数可选
# 可选参数 我们需要在闭包或控制器中设置默认值
# 必选参数放在可选参数的前面(这是由于默认参数一般放在后面)
# 必选参数和可选参数 和 闭包或控制器动作 (一一对应(和参数名字不必保持一致))
Route::post('photos/{id}/edit/{value?}', function($id, $value=null){});
where 正则验证
  • 使用正则约束还有一个好处就是避免了 user/{id} 和 user/{name} 的混淆
# where 方法约束路由参数
@method static \Illuminate\Routing\RouteRegistrar 
where(array  $where)

# 示例
Route::get('user/{name}', function( $name ){
    return $name;
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    // $id 必须是数字
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    // 同时指定 id 和 name 的数据格式
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
全局约束
pattern(string $key, string $pattern)
# 使用全局约束 在提供者 RouteServiceProvider 类的boot中定义
public function boot()
{
    Route::pattern('id', '[0-9]+');
    parent::boot();
}
检查当前路由
# 判断当前路由名称是否已设置路由别名 (使用as或name函数)
/**
  * Determine whether the route's name matches the given patterns.
  *
  * @param  dynamic  $patterns
  * @return bool
  */
public function named(...$patterns)
{
    // 获取当前环境设置的所有路由别名 as
    if (is_null($routeName = $this->getName())) {
        return false;
    }

    // 判断当前参数是否存在路由别名中
    foreach ($patterns as $pattern) {
        if (Str::is($pattern, $routeName)) {
            return true;
        }
    }

    return false;
}

/**
  * Determine if a given string matches a given pattern.
  *
  * @param  string|array  $pattern
  * @param  string  $value
  * @return bool
  */
public static function is($pattern, $value)
{
    // 转换成数组
    $patterns = Arr::wrap($pattern);

    if (empty($patterns)) {
        return false;
    }

    foreach ($patterns as $pattern) {
        // If the given value is an exact match we can of course return true right
        // from the beginning. Otherwise, we will translate asterisks and do an
        // actual pattern match against the two strings to see if they match.
        if ($pattern == $value) {
            return true;
        }

        // 给pattern字符串#添加反斜杠 \#
        $pattern = preg_quote($pattern, '#');

        // Asterisks are translated into zero-or-more regular expression wildcards
        // to make it convenient to check if the strings starts with the given
        // pattern such as "library/*", making any string check convenient.
        $pattern = str_replace('\*', '.*', $pattern);

        // # 边界符 
        // ^ 匹配行开始
        // \z 匹配行结尾
        if (preg_match('#^'.$pattern.'\z#u', $value) === 1) {
            return true;
        }
    }

    return false;
}
资源路由
# 创建一个资源控制器命令(该命令会在app/http/Controllers/下创建PhotoController.php控制器)
php artisan make:controller PhotoController --resource
# 注册资源路由:
Route::resource('photos','PhotoController');
# 资源路由,资源控制器:自动创建多个控制器方法
路由使用_第2张图片
# 比如:在app/http/Controllers/Admin/目录下创建 PhotoController.php资源路由
php artisan make:controller Admin\PhotoController --resoucre
# 该命令会自动创建 index()、create()、store()、show()、edit()、update()、destory()方法
  • 资源路由注册 - 更多参看控制器
@method static \Illuminate\Routing\PendingResourceRegistration 
esource(string $name, string $controller, array $options = [])
# 创建部分资源路由(PhotoController.php文件部分动作生效)
# only : 表示仅仅需要的动作
Route::resource('photo','Admin\\PhotoController',[
    //> 仅index和show动作生效
    'only' => ['index','show']
]);
# except : 排除指定动作外的其他动作
Route::resource('photo','Admin\\PhotoController',[
    //> except 排除指定动作
    'execpt' => ['create','store','update','destory']
])
# 命名资源路由:在使用route()辅助函数时(相当于name()方法)
Route::resource('photos','Admin\\PhotoController',[
    //> 修改资源路由名称
    'names' => [ 
        'index' => 'b.index', 
        'create'=>'b.create' 
    ]
])

# 命名资源路由参数
# 资源路由参数:会基于资源名称的单数格式为资源路由创建路由参数
# 比如:PhotoController控制器的/photos/{photo}/edit
# 使用parameters参数覆盖Laravel资源路由这一默认设置
Route::resource('photos','Admin\\PhotoController',[
    'parameters' => [
        'photos' => 'bm'
    ]
]);
# 上面的路由也就会修改为/photo/{bm}这种形式
# 资源路由器 在使用 默认动作之外的时候
# 在使用资源路由中其他方法时,路由注册在资源路由之前
Route::get('photos/foo', 'Admins\\PhotoController@method');   //资源路由里添加动作method
Route::resource('photos', 'Admin\\PhotoController');
API资源路由
# api资源路由参看 - 资源路由(上)
# 资源路由 apiResource 自动排除 create 和 edit 动作
@method static \Illuminate\Routing\PendingResourceRegistration 
apiResource(string $name, string $controller, array $options = [])
@method static void apiResources(array $resources)

# 注册多个资源控制器
Route::apiResources([
    'posts' => 'PostController',
    'photos' => 'PhotoController'
]);
# 资源路由 API控制器生成
php artisan make:controller API/PostController --api
  • 表单伪造、CSRF防护
# 表单伪造
# 由于HTML表单不能发起PUT、PATCH、DELETE请求
# 笔者已经测试:伪造的请求;在请求头中还是以get或post请求后台服务器
{{ method_field('PUT') }}  # 表单隐藏域;伪造HTTP请求时使用
# POST请求需要添加
{{ csrf_field() }}
# CSRF防护 - 更多用法参考CSRF保护
# web.php路由中PUT、POST、DELETE的HTML表单需要一个CSRF令牌字段
{{ csrf_field() }} ...
当前路由信息
# current():获取当前访问路由的详细信息(Route对象)
@method static \Illuminate\Routing\Route current()
# currentRouteName():获取当前路由的名称(就是name()函数或as()函数设置的值)
@method static string|null currentRouteName()
# currentRouteAction():获取当前路由的命名空间以及控制器及方法
@method static string|null currentRouteAction()

# 示例
Route::as('s.s')->get('/s', function (){
    dump(Route::current());             // route对象
    dump(Route::currentRouteName());    // s.s
    dump(Route::currentRouteAction());  // null 当前无命名空间以及控制器及方法
});
路由模型绑定
/**
 * Register a model binder for a wildcard.
 *
 * @param  string  $key
 * @param  string  $class
 * @param  \Closure|null  $callback
 * @return void
 *
 * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
 */
public function model($key, $class, Closure $callback = null)
{
    $this->bind($key, RouteBinding::forModel($this->container, $class, $callback));
}

/**
 * Add a new route parameter binder.
 *
 * @param  string  $key
 * @param  string|callable  $binder
 * @return void
 */
public function bind($key, $binder)
{
    $this->binders[str_replace('-', '_', $key)] = RouteBinding::forCallback(
        $this->container, $binder
    );
}
  • 隐式绑定
  • 由于类型声明了 Eloquent 模型 App\User,对应的变量名 $user 会匹配路由片段中的 {user},
  • 这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。
  • 如果匹配模型实例在数据库中不存在,会自动生成 404 响应
# Id注入 依赖注入 User类 user参数默认匹配users表中的id字段 id = user隐
# 隐式绑定 {user} 对应 $user 变量
Route::get('users/{user}', function (App\User $user) {
    dump( $user->email );  // 获取id=user 数据中的 email字段
    dump( $user->getAttribute('email') );  // 获取id=user 数据中的 email字段
    dump( $user->getAttribute('name') );  // 获取name值
    dump( $user->getRouteKeyName() );  // 获取主键key 默认id getRouteKeyName()可修该该值
    // $user->getRouteKey() === $user->getAttribute($user->getRouteKeyName())
    dump( $user->getRouteKey() );  // 获取主键值 及user值
});

# 如果你想要在隐式模型绑定中使用数据表的其它字段而不是 id 字段,
#可以重写 Eloquent 模型类的 getRouteKeyName 方法,
# 以 User 模型为例,可以在该模型类中添加这个方法
# Model 模型 中添加 users表中 getRouteKeyName = user 参数
public function getRouteKeyName()
{
    //  parent::getRouteKeyName() <=> 主键 id
    return parent::getRouteKeyName(); // TODO: Change the autogenerated stub
}
  • 显式绑定
# 显式绑定 不在遵循 {user} 对应 $user变量
# 显式绑定使用Route::model方法指定参数绑定
# 在服务提供者RouteServiceProvider类的boot方法中定义绑定
public function boot(){
    parent::boot();
    // 绑定 user_model参数 到 App\User
    Route::model('user_model', App\User::class);
}
// 路由绑定
Route::get('users/{user_model}', function(\App\User $user){
    dump( $user->email );
});
# 如果匹配的模型实例在数据库不存在,会自动生成并返回 HTTP 404 响应
  • 自定义逻辑
# 使用Route::bind方法绑定
# 传递到 bind 方法的闭包会获取到 URI 请求参数中的值,并且返回你想要在该路由中注入的类实例
# 服务提供者 RouteServiceProvider 类的boot方法中
public function boot(){
    parent::boot();
    
    Route::bind('user', function($value){
        // $value = {user} 参数
        // return 返回值 Route路由值
        return User::where('id',$value)->first() ?? abort(404);
    });
}

# 路由文件中定义 Route::bind() user 对应 Route::get() {user}
Route::get('users/{user}', function($user){
    // {user} => Route::bind() -> $user
    // $user 来自 Route::bind()方法返回的值
    dump( $user->toArray() );  // 对象转换为数组
});
路由参数转换
# 一下方法处理路由参数转化
@method static \Illuminate\Routing\Route 
substituteBindings(\Illuminate\Support\Facades\Route $route)
@method static void 
substituteImplicitBindings(\Illuminate\Support\Facades\Route $route)

# 参考 中间件 \Illuminate\Routing\Middleware\SubstituteBindings
# https://laravel-china.org/articles/5515/want-to-change-the-routing-parameters-to-the-type-you-want-the-use-of-substitutebindings-middleware-and-source-code-analysis?order_by=vote_count&
兜底路由
  • 当所有其他路由都未能匹配请求 URL 时所执行的路由
# 访问路由地址不存在时,执行以下内容
Route::fallback(function (){
    echo "fallback";
});
路由缓存
  • 路由缓存不会作用于基于闭包的路由。
  • 要使用路由缓存,必须将闭包路由转化为控制器路由
# 生成路由缓存
php artisan route:cache
# 移除缓存路由文件
php artisan route:clear
路由文件自定义
  • App\Providers\RouteServiceProvider 路由服务提供者
mapApiRoutes();
        // 加载web.php路由文件
        $this->mapWebRoutes();

        // 路由文件加载 - 自定义
        $this->mapWebsRoutes();
    }

    /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapWebRoutes()
    {
        // 加载web中间件组
        // $this->namespace 命名空间
        // group加载 routes/web.php 文件路由
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

    /**
     * Define the "api" routes for the application.
     *
     * These routes are typically stateless.
     *
     * @return void
     */
    protected function mapApiRoutes()
    {
        // prefix 路由前缀
        // api 中间件
        // $this->namespace 命名空间
        // group 加载 routes/api.php 路由文件
        Route::prefix('api')
             ->middleware('api')
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }

    /**
     * 自定义 路由规则
     * @return void
     */
    protected function mapWebsRoutes(){
        // 获取routes/routes目录下所有.php文件 返回数组
        foreach ( glob(base_path('routes'.DIRECTORY_SEPARATOR.'web'.DIRECTORY_SEPARATOR).'*.php' ) as $fileName ) {
            // basename() 函数路径中的文件名部分  xxxx.php
            $fileName = basename( $fileName );
            // 获取 xxxx.php 中的 xxxx内容
            $prefix = substr( $fileName,0,strrpos($fileName,'.') );
            // ucfirst(string) 将string首字母转换成大写 并返回
            $nameSpace = ucfirst($prefix);
            // 注册当前路由
            // 注册 web 中间件组
            // 设置命名空间 $this->namespace."\\{$nameSpace}"
            // group 加载路由文件
            Route::middleware('web')
                ->namespace( $this->namespace."\\{$nameSpace}" )
                ->group( base_path('routes'.DIRECTORY_SEPARATOR.'web'.DIRECTORY_SEPARATOR."{$fileName}") );
        }
    }
}
  • 路由文件
路由使用_第3张图片
  • 对应控制器
路由使用_第4张图片

你可能感兴趣的:(路由使用)