控制器:控制器用来处理业务的,不应该处理逻辑,如果是小项目可以把逻辑写到控制器里,大点的项目应该抽离出来业务处理层如下:services业务处理层:比如:获取值,验证值,异常捕获
命名规则:控制器名:用大驼峰命名 如:HelloController; 方法名:用小驼峰 如:helloWorld();成员变量:小驼峰 或者 _名称
创建控制器(可以自定义目录):php artisan make:controller UserController php artisan make:controller Admin/UserController
控制器简单实用实例:控制器简单使用:迁移数据库1.创建数据库 laravel6 配置数据库连接.envDB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=laravel6DB_USERNAME=rootDB_PASSWORD=123456782.检测默认连接\config\database.php 'default' => env('DB_CONNECTION', 'mysql'),
3.数据库迁移命令:php artisan migrate可能会出现42000 1071错误 ,因为创建表的字段名称过长,如下解决在 \Providers\AppServiceProvider.php 中
控制器简单使用:迁移数据库1.创建数据库 laravel6 配置数据库连接.envDB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=laravel6DB_USERNAME=rootDB_PASSWORD=123456782.检测默认连接\config\database.php 'default' => env('DB_CONNECTION', 'mysql'),
3.数据库迁移命令:php artisan migrate可能会出现42000 1071错误 ,因为创建表的字段名称过长,如下解决在 \Providers\AppServiceProvider.php 中
模型工程写入php artisan tinkerPsy Shell v0.9.9 (PHP 7.3.10 — cli) by Justin Hileman>>> factory(App\User::class,5)->create(); User模型 写入5条数据数据库中写入了5条数据
view视图展示路由:Route::get("show/{id}","UserController@show");UserController控制器如下写:public function show($id){ return view("user.profile",["user" => User::findOrNew($id)]);}传递 id 查出一数据显示创建视图 \view\user\profile.blade.php{{$user}}
模型工程写入php artisan tinkerPsy Shell v0.9.9 (PHP 7.3.10 — cli) by Justin Hileman>>> factory(App\User::class,5)->create(); User模型 写入5条数据数据库中写入了5条数据
view视图展示路由:Route::get("show/{id}","UserController@show");UserController控制器如下写:public function show($id){ return view("user.profile",["user" => User::findOrNew($id)]);}传递 id 查出一数据显示创建视图 \view\user\profile.blade.php{{$user}}
控制器加载原理:在服务提供者中 RouteServiceProvider.php 中,可以自定义 命名空间功能 与 业务抽离 不同的控制器目录下
控制器 & 命名空间:需要着重指出的是,在定义控制器路由时我们不需要指定完整的控制器命名空间。因为 `RouteServiceProvider` 会在一个包含命名空间的路由组中加载路由文件,我们只需要指令类名中 `App\Http\Controllers` 命名空间之后的部分就可以了。
单个行为控制器:如果你想要定义一个只处理单个行为的控制器,你可以在控制器中放置一个 `__invoke` 方法: 你可以通过 Artisan 命令工具里的 `make:controller` 命令中的 `--invokable` 选项来生成一个可调用的控制器: php artisan make:controller ShowProfile --invokable
控制器中间件:请求流程:用户请求 -> 中间件 -> 控制器 -> 控制器方法例如:class UserController extends Controller{ public function __construct() { $this->middleware("auth"); //如果没有登录会重定向到 login 路由中 $this->middleware("log")->only("test"); // 只执行当前中间件中 index 之外的方法 [可以是数组] 类似于白名单 $this->middleware("subscribed")->except("store"); //执行当前中间件中 store 之外的方法 [可以是数组] 类似于黑名单// dd($this); }
// public function show($id) { return view("user.profile",["user" => User::findOrNew($id)]); }
// pubf + tab 快捷键生成方法 public function index() { echo "this is index()"; }
// 白名单方法test() public function test() {
}
}如上代码会读取log文件访问 log /Users/xxxx/wwwn/test.laravel6.com/storage/logs错误: Route [login] not defined. 原因: 没有登录的时候回执行 Middleware\Authenticate.php 重定向方法 protected function redirectTo($request) { if (! $request->expectsJson()) {
return route('login'); } }错误:需要对象式的参数 log() expects parameter 1 to be float, object given$this->middleware("log")这个中间件的错误提示
可以通过闭包注册中间件同时,控制器还允许你使用一个闭包来注册中间件。这为不定义整个中间件类的情况下为单个控制器定义中间件提供了一种方便的方法:$this->middleware(function ($request, $next) { return $next($request);});
Http请求处理:用户请求 -> Illuminate\Http\Request请求类 ->laravel 中 post请求 Cookie携带有 CRSF令牌,如果想要post get方式都可以请求需要注释掉 CRSF令牌校验在 kernel.php 如下: // \App\Http\Middleware\VerifyCsrfToken::class,public function store(Request $request, $name=null){ $name = $request->input('name'); // 既可以获取get 也可以请求post参数 $get = $request->get('name'); $post = $request->post('name'); $all = $request->all('name'); dd($name,$get,$post,$all); return $name;}
一个路由中可以,既有post参数,也有get地址栏的 where参数 Route::any("stores/{id}/{where?}","UserController@stores"); http://test.laravel6.com:8002/stores/333/age?u=getUser&s=shengri打印:"333""age"array:2 [ "u" => "getUser" "s" => "shengri"]
旧数据:Laravel 允许你在两次请求之间保持数据。这个特性在有效性校验出错后重新填充表单时非常有用。比如:保存用户名!1.1 存储到session中//读取 session数据$name = $request->old("name"); // post 方式请求的 存储到session$m = $request->old("m"); // where get 方式请求的 存储到sessionvar_dump($name,$m);//dd($name,$m);会把 请求参数写入session文件 \storage\framework\session\.......
文件:上传与下载php artisan make:controller FileController当然你也可以使用 `hasFile` 方法判断请求中是否存在指定文件:if ($request->hasFile('photo')) {}验证成功上传:除了检查上传的文件是否存在外,你也可以通过 `isValid` 方法验证上传的文件是否有效:if ($request->file('photo')->isValid()) {}文件路径 & 扩展名:`UploadedFile` 类还包含访问文件的全路径和扩展名的方法。 `extension` 方法会根据文件内容判断文件的扩展名。该扩展名可能会和客户端提供的扩展名不同:$path = $request->photo->path(); //临时路径$extension = $request->photo->extension(); //后缀名
存储上传文件:要存储上传的文件,先配置好 [文件系统](https://learnku.com/docs/laravel/6.0/filesystem)。 你可以使用 `UploadedFile` 的 `store` 方法把上传文件移动到你的某个磁盘上,该文件可能是本地文件系统中的一个位置,甚至像 Amazon S3 这样的云存储位置。`store` 方法接受相对于文件系统配置的存储文件根目录的路径。这个路径不能包含文件名,因为系统会自动生成唯一的 ID 作为文件名。`store` 方法还接受可选的第二个参数,用于存储文件的磁盘名称。这个方法会返回相对于磁盘根目录的文件路径:$path = $request->photo->store('images'); // 上传的文件默认保存在 storage\app\images\xxxxxx$path = $request->photo->store('images', 's3');如果你不想自动生成文件名,那么可以使用 `storeAs` 方法,它接受路径、文件名和磁盘名作为其参数:$path = $request->photo->storeAs('images', 'filename.jpg');$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
响应:字符串,数组,视图,响应信息可以自定义,针对不同的响应结果,返回对应的响应状态string 类型响应 text/html; charset=UTF-8arr 响应类型 application/json3.4.2 Response 对象:通常,我们并不只是从路由动作简单返回字符串和数组,大多数情况下,都会返回一个完整的`Illuminate\Http\Response` 实例或 [视图](https://learnku.com/docs/laravel/6.0/views)。
返回完整的 `Response` 实例允许你自定义响应的 HTTP 状态码和响应头信息。 `Response` 实例 继承自 `Symfony\Component\HttpFoundation\Response` 类, 该类提供了各种构建 HTTP 响应的方法:
Route::get('home', function () { return response('Hello World', 200) ->header('Content-Type', 'text/plain');});
添加响应头:大部分的响应方法都是可链式调用的,使得创建响应实例的过程更具可读性。例如,你可以在响应返回给用户前使用 `header` 方法为其添加一系列的头信息:return response($content) ->header('Content-Type', $type) ->header('X-Header-One', 'Header Value') ->header('X-Header-Two', 'Header Value');或者,你可以使用 `withHeaders` 方法来指定要添加到响应的头信息数组:return response($content) ->withHeaders([ 'Content-Type' => $type, 'X-Header-One' => 'Header Value', 'X-Header-Two' => 'Header Value', ]);
重定向:重定向响应是 `Illuminate\Http\RedirectResponse` 类的实例,并且包含用户需要重定向至另一个 URL 所需的头信息。Laravel 提供了几种方法用于生成 `RedirectResponse` 实例。其中最简单的方法是使用全局辅助函数 `redirect`:Route::get("home",function (){ return redirect("string"); // 重定向到指定路由});Route::get("home",function (){ return redirect("http://www.baidu.com"); //重定向到 外部的连接url});Route::get("cdx",function (){ return redirect()->away('arr'); // 重定向到指定路由});
有时候你可能希望将用户重定向到之前的位置,比如提交的表单无效时。这时你可以使用全局辅助函数 `back` 来执行此操作。由于这个功能利用了 [会话控制](https://learnku.com/docs/laravel/6.0/session),请确保调用 `back` 函数的路由使用 `web` 中间件组或所有 Session 中间件:Route::post('user/profile', function () { // 验证请求 return back()->withInput();});
重定向到命名路由:如果调用不带参数的辅助函数 `redirect` 时,会返回 `Illuminate\Routing\Redirector` 实例。这个实例允许你调用 `Redirector` 上的任何方法。例如为命名路由生成 `RedirectResponse`,可以使用 `route` 方法:return redirect()->route('login');如果路由中有参数,可以将其作为第二个参数传递到 `route` 方法:return redirect()->route('profile', ['id' => 1]);
重定向到控制器行为:还可以生成到 [controller action](https://learnku.com/docs/laravel/6.0/controllers) 的重定向。要达到这个目的,只要把 控制器 和 action 的名称传递给 `action` 方法。记住,不需要传递控制器的全部命名空间,Laravel 的 `RouteServiceProvider` 会自动将其设置为基本控制器的命名空间:return redirect()->action('HomeController@index');如果控制器路由需要参数,可以将其作为 `action` 方法的第二个参数:return redirect()->action( 'UserController@profile', ['id' => 1]);重定向到外部域名:有时候你需要重定向到应用外的域名。调用 `away` 方法可以达到此目的,它会创建一个不带有任何额外的 URL 编码、有效性校验和检查的 `RedirectResponse` 实例:return redirect()->away('https://www.google.com');其他的响应类型:`response` 助手可以用于生成其它类型的响应实例。当还带参数调用 `response` 助手时,返回 `Illuminate\Contracts\Routing\ResponseFactory` [contract](https://learnku.com/docs/laravel/6.0/contracts) 的一个实现。这个契约提供了几个用于生成响应的方法:视图响应:如果需要把 [视图](https://learnku.com/docs/laravel/6.0/views) 作为响应内容返回的同时,控制响应状态和头信息,就需要调用 `view` 方法,如果不需要传递自定义的 HTTP 状态码和自定义头信息,还可以使用全局的 `view` 辅助函数。return response() ->view('hello', $data, 200) ->header('Content-Type', $type);JSON响应:`json` 自动将 `Content-Type` 头信息设置为 `application/json`,同时使用 PHP 的 `json_encode` 函数将给定的数组转换为 JSON :return response()->json([ 'name' => 'Abigail', 'state' => 'CA']);如果想要创建 JSONP 响应,可以结合 `withCallback` 方法使用 `json` 方法:return response() ->json(['name' => 'Abigail', 'state' => 'CA']) ->withCallback($request->input('callback'));
文件下载:1.设置http响应头2.下载文件的名称,大小return response()->download($pathToFile);return response()->download($pathToFile, $name, $headers);return response()->download($pathToFile)->deleteFileAfterSend();
RESTful 风格:定义:REST 是 “呈现状态转移(REpresentational State Transfer)” 的缩写。或许可以这样来定义它:一种 API 的架构风格,在客户端和服务端之间通过呈现状态的转移来驱动应用状态的演进。
约束:要让应用 RESTful 化,需要遵循以下约束。遵循了这些约束的分布式系统,就会拥有如下非功能属性:性能,伸缩性,易用性,扩展性,可见性,可移植性和可靠性。
CS 模式:CS 模式通过分离客户端和服务器端的关注点,让客户端不再关注数据的存储问题,从而提高客户端代码的可移植性。另一方面,服务器端不再关注用户界面和用户状态,从而变得更简单,提高了伸缩性。服务器端跟客户端可以独立开发,只要它们都遵守契约。
无状态:客户端上下文在多个请求之间是绝不会保存在服务器上的。每个请求必须包含必要的信息。无状态的服务器通过快速释放资源和简化实现提高了可伸缩性。可靠性使得从局部失败中恢复变得容易。很明显,监控系统不必通过考虑单个请求来判断请求的性质。 无状态服务器的一个缺点是降低了网络性能,因为所有需要的数据必须在每次请求中发送。
可缓存:REST 应用程序是 web 系统,因此客户端和中间层可以缓存响应。响应必须被定义为可缓存或不可缓存的,以防客户端重复使用旧数据导致降低可靠性。如果缓存中的陈旧数据与已生成的请求的数据显著不同,则由服务器处理请求。缓存可以消除一些客户端和服务器之间的交互,这就提升了可伸缩性、效率和通过减少平均延迟达到的用户可感知的性能。
统一的接口:使用统一的接口降低了系统复杂度和耦合度,让系统的不同部分可以独立演化。稍后会解释 URI,资源和超媒体是如何通过生成标准接口来提升用户交互可见性,降低系统复杂度,促进系统组件独立演化的。但是我们需要在效率方面做出妥协,毕竟消息是通过标准格式传输的,并不能满足所有应用对消息格式的要求。
分层的系统:分层系统通过约束组件的行为来降低系统复杂度,组件不能越过它们的媒介层去访问其它层。通过组件的阻断来保持层间的独立性。遗留的组件可以被封装成新的层,不让旧的客户端访问。媒介层可以通过负载均衡来提升伸缩性。分层系统存在的主要不足,是它给数据处理增加了一些额外的开销,增加了延迟,对用户体验有所影响。
按需编码:
REST 允许客户端通过下载执行脚本来扩展它们的功能,简化了客户端,也提升了扩展性。但这同时也降低了可见性,所以这个约束不是必须遵循的。
元素:REST 提供了以下几种元素来构建无状态,可伸缩的 web API。
HTTP协议:资源URI超媒体HTTP - 文本传输协议
REST 一般使用 HTTP 作为它的传输协议,因为 HTTP 提供了一些很好用的特性,如 HTTP 动词,状态码和头部信息
HTTP 动词:HTTP 并没有定义很多动词来描述 web 服务中可能出现的行为,它只用了一个标准动词集合来处理各种相似情况,从而让 API 变得更直观。每个动词通过两种属性的组合来满足不同的场景需求。
幂等性:操作可以被重复执行,就算在失败以后。安全性:对客户端来说操作不会产生副作用。
GET:用来从服务器端读取状态。这个操作是安全的,所以它可以被执行很多次而不会对数据有任何影响,也就是说执行它一次跟执行十次是一样的效果。从幂等性方面来看,多次请求跟单个请求总能得到相同的结果。
POST:一般用来在服务器端创建某种状态。这个操作不具备幂等性跟安全性,所以多次请求会在服务器端创建多个资源。因为 POST 是不幂等的, 所以不应该被用来做跟金钱有关系的操作,试想一次失败的请求如果被执行多次,那么很可能转账或者支付也被执行了多次。
PUT:虽然它也可以被用来创建状态,但主要还是用来在服务器端更新状态的。它是幂等的,但不安全,因为它会改变服务端的状态。因为它的幂等性,PUT 可以被用来处理跟金钱有关系的操作。
DELETE:用来在服务器端删除状态。它也是幂等非安全的,因为它会移除服务端的状态。它之所以是幂等的,是因为重复删除一个状态的结果是一样。
响应状态码:HTTP 在请求资源的响应里提供了元数据信息,也就是状态码。它们是 web 平台之所以能用来构建分布式系统的重要因素。它们被分为以下几类:- 1xx —— 元数据- 2xx —— 正确的响应- 3xx —— 重定向- 4xx —— 客户端错误- 5xx —— 服务端错误
头部信息:HTTP 在消息头部里为请求响应提供了额外信息。每个头部由大小写敏感的关键字和值组成,中间用冒号隔开。头部信息被分为以下几类:一般头部:在请求跟响应里都有,跟消息体里传输的数据没有关系。请求头部:更多的是关于被请求资源或者客户端的信息。响应头部:响应的额外信息。实体头部:消息体的额外信息,比如 content-length 或 MIMI-type。
资源:资源可以是由系统暴露出来的任何具有唯一标识的东西。资源在应用领域跟客户端之间建立起了联系。一张图片,一个表格,或者它们的集合,都被看作资源。资源通过某种呈现方式被获取或被创建 (XML,JSON 等)。 我们与之打交道的是资源的呈现形式,并不是资源本身,这个跟值传递有点像。根据之前对 REST 的定义,资源代表了在网络上传输的文档。服务器端关心资源的状态,因为它们代表了领域的状态。而客户端只是获取或者发送资源的呈现状态,从而让应用的状态发生变化。客户单关心的是应用的状态,因为这些状态的变化跟应用所要达成的目标有关系。 资源的名字都应该是名词性质的,它们代表的是系统中领域的概念,并用 URI 标识。
URIs (Uniform Resource Identifiers)URIs 用来唯一标识资源。要访问或者操作一个资源,最起码要知道资源的地址。它们由协议 + 服务器地址 + 路径组成。客户端不应该与资源的 URI 有太多耦合,因为服务端可能随意改变它们的值。在这一点上,超媒体更具优势。它提供了一种解耦客户端跟 URI 的方式,并在应用协议中加入新的语义。
资源控制器:简介:Laravel 的资源路由将典型的「CURD (增删改查)」路由分配给具有单行代码的控制器。例如,你希望创建一个控制器来处理保存 "照片" 应用的所有 HTTP 请求。使用 Artisan 命令 `make:controller` ,我们可以快速创建这样一个控制器:php artisan make:controller PhotoController --resource这个命令将会生成一个控制器 `app/Http/Controllers/PhotoController.php` 。其中包括每个可用资源操作的方法。
接下来,你可以给控制器注册一个资源路由:Route::resource('photos', 'PhotoController');
这个单一的路由声明创建了多个路由来处理资源上的各种行为。生成的控制器为每个行为保留了方法,包括了关于处理 HTTP 动词和 URLs 的声明注释。
你可以通过将数组传参到 `resource` 方法中的方式来一次性的创建多个资源控制器:Route::resources([ 'photos' => 'PhotoController', 'posts' => 'PostController']);
资源控制器操作处理:
| HTTP 方法 | URI | 动作 | 路由名称 || --------- | ---------------------- | ------- | -------------- || GET | `/photos` | index | photos.index || GET | `/photos/create` | create | photos.create || POST | `/photos` | store | photos.store || GET | `/photos/{photo}` | show | photos.show || GET | `/photos/{photo}/edit` | edit | photos.edit || PUT/PATCH | `/photos/{photo}` | update | photos.update || DELETE | `/photos/{photo}` | destroy | photos.destroy |
制定资源模型:如果你使用了路由模型绑定,并且想在资源控制器的方法中使用类型提示,你可以在生成控制器的时候使用 `--model`选项:php artisan make:controller PhotoController --resource --model=Photo
部分资源路由:Route::resource('photos', 'PhotoController')->only([ 'index', 'show']);Route::resource('photos', 'PhotoController')->except([ 'create', 'store', 'update', 'destroy']);
API 资源路由:当声明用于 APIs 的资源路由时,通常需要排除显示 HTML 模板的路由(如 `create` 和 `edit` )。为了方便起见,你可以使用 apiResource 方法自动排除这两个路由:
Route::apiResource('photos', 'PhotoController');
你可以传递一个数组给 `apiResources` 方法来同时注册多个 API 资源控制器:Route::apiResources([ 'photos' => 'PhotoController', 'posts' => 'PostController']);
要快速生成不包含 `create` 或 `edit` 方法的用于开发接口的资源控制器,请在执行 `make:controller` 命令时使用 `--api` 开关:php artisan make:controller API/PhotoController --api
命名资源路由:默认情况下,所有的资源控制器行为都有一个路由名称。你可以传入 names 数组来覆盖这些名称:Route::resource('photos', 'PhotoController')->names([ 'create' => 'photos.build']);命名资源路由参数:
默认情况下,`Route::resource` 会根据资源名称的「单数」形式创建资源路由的路由参数。你可以在选项数组中传入 `parameters` 参数来轻松地覆盖每个资源。`parameters` 数组应该是资源名称和参数名称的关联数组Route::resource('users', 'AdminUserController')->parameters([ 'users' => 'admin_user']);
上例将会为资源的 `show` 路由生成如下的 URI :/users/{admin_user}
php artisan make:controller Api/ResController --resourcephp artisan route:list