Laravel 和 react 是用于构建现代 Web 应用程序的两种流行的 Web 开发技术。Laravel 是一个突出的服务器端 php框架,而 React 是一个客户端javascript库。本教程作为 Laravel 和 React 的介绍,将它们结合起来创建一个现代 Web 应用程序。
在现代 Web 应用程序中,服务器通过一些 api(应用程序编程接口)端点管理后端的工作有限。客户端向这些端点发送请求,服务器返回响应。但是,服务器并不关心客户端如何渲染视图,这完全符合关注点分离原则。这种架构允许开发人员为 Web 和不同设备构建健壮的应用程序。
在本教程中,我们将使用最新版本的 Laravel 5.5 版来创建 restful 后端 API。前端将包含用 React 编写的组件。我们将构建一个资源丰富的产品列表应用程序。本教程的第一部分将更多地关注 Laravel 概念和后端。让我们开始吧。
介绍
Laravel 是一个为现代 Web 开发的 PHP 框架。它有一种表达性的语法,有利于约定而不是配置范式。Laravel 具有开箱即用的项目启动所需的所有功能。但就个人而言,我喜欢 Laravel,因为它将 PHP 开发变成了完全不同的体验和工作流程。
另一方面,React 是 Facebook 开发的一个流行的 JavaScript 库,用于构建单页应用程序。React 帮助您将视图分解为组件,其中每个组件描述应用程序 UI 的一部分。基于组件的方法具有组件可重用性和模块化的额外好处。
为什么选择 Laravel 和 React?
如果您正在为 Web 开发,您可能倾向于为服务器和客户端使用单个代码库。然而,并不是每家公司都给予开发者使用他们选择的技术的自由,并且有一些很好的理由。为整个项目使用 javaScript 堆栈是当前的常态,但没有什么能阻止您为服务器端和客户端选择两种不同的技术。
那么 Laravel 和 React 结合得如何呢?很好,事实上。尽管 Laravel 已经记录了对vue .js 的支持,这是另一个 JavaScript 框架,但我们将在前端使用 React,因为它更受欢迎。
先决条件
在开始之前,我将假设您对 RESTful 架构以及 API 端点的工作方式有基本的了解。此外,如果你之前有 React 或 Laravel 的经验,你将能够充分利用本教程。
但是,如果您对这两个框架都不熟悉,请不要担心。本教程是从初学者的角度编写的,您应该能够轻松赶上。您可以在GitHub 上找到本教程的源代码。
安装和设置你的 Laravel 项目
Laravel 使用Composer来管理所有的依赖。因此,在开始使用 Laravel 之前,请在您的机器上下载并安装Composer。您可能还需要配置路径环境变量,以便全局访问 Composer。
运行以下命令下载 laravel 安装程序。
composer global require "laravel/installer"
如果您已正确配置$PATH
变量并添加~/.composer/vendor/bin
到路径中,您应该能够生成一个新的 Laravel 项目,如下所示:
laravel new PROJECT-NAME
或者,您可以使用 Composer 创建一个没有 laravel 安装程序的新项目。
composer create-project --prefer-dist laravel/laravel blog
如果一切顺利,您应该能够在http://localhost:8000
.
php artisan serve
注意:Artisan 是一个命令行工具,在使用 Laravel 时你离不开它。Artisan 接受大量命令,可让您为应用程序生成代码。运行 php
artisan list
以查看所有可用的工匠命令。
配置环境
您的应用程序将在根目录中有一个.env文件。所有特定于环境的配置信息都在这里声明。如果您还没有为您的应用程序创建一个数据库,则将数据库详细信息添加到.env文件中。
DB_CONNECTION= mysql DB_HOST=127.0.0.1DB_PORT=3306 DB_dataBASE=sampledb DB_USERNAME=rootDB_PASSWORD=
了解模型、路由和控制器
Laravel 是一个遵循模型-视图-控制器(MVC)架构的框架。从广义上讲,MVC 帮助您将数据库查询(模型)与与如何处理请求(控制器)和如何呈现布局(视图)相关的逻辑分开。下图展示了典型 Laravel 应用程序的工作原理。
Laravel 的架构。控制器返回响应,因此不需要视图层。
由于我们正在使用 Laravel 构建 API,因此我们将讨论仅限于模型和控制器。我们将在本教程的第二部分回顾我们创建视图的选项。
路由器
当服务器收到一个 HTTP 请求时,Laravel 会尝试将它与在任何路由文件中注册的路由匹配。所有路由文件都位于 routes 目录中。routes/web.php托管 Web 界面的路由,而routes/api.php托管 API 的路由。在api.php中注册的路由将带有前缀/api
(如在 localhost:3000/api 中)。如果您需要更改此行为,您应该前往 /app/Providers/RouteServiceProvider.phpRouteServiceProvider
中的类 并在那里进行更改。
由于我们正在构建产品列表应用程序,因此这里是 API 的端点以及与这些端点关联的 HTTP 操作。
GET
/products/
:检索所有产品。GET
/product/{id}
:检索与id
.post
/products
:创建一个新产品并将其插入数据库。PUT
/products/{id}
:更新与id
.DELETE
/products/{id}
:删除给定的产品id
。
让我们正确使用术语。GET、POST、PUT 和 DELETE 是构建 RESTful 服务所必需的 HTTP 动词(通常称为 HTTP 方法)。/products
是与产品资源关联的 URI。HTTP 方法请求服务器对给定资源执行所需的操作。
GET、POST、PUT 和 DELETE 是常用的 REST 动作
路由器允许您声明资源的路由以及针对该资源的 HTTP 方法。这是一个返回一些硬编码数据的示例路由文件。
路线/api.php
/** ** Basic Routes for a RESTful service: ** ** Route::get($uri, $callback); ** Route::post($uri, $callback); ** Route::put($uri, $callback); ** Route::delete($uri, $callback); ** **/ Route::get('products', function () { return response(['Product 1', 'Product 2', 'Product 3'],200); }); Route::get('products/{product}', function ($productId) { return response()->json(['productId' => "{$productId}"], 200); }); Route::post('products', function() { return response()->json([ 'message' => 'Create success' ], 201); }); Route::put('products/{product}', function() { return response()->json([ 'message' => 'Update success' ], 200); }); Route::delete('products/{product}',function() { return response()->json(null, 204); });
如果要验证路由是否按预期工作,则应使用 POSTMAN 或curl之类的工具。
产品型号
products 资源需要一个可以与数据库交互的模型。模型是位于数据库之上的层,隐藏了所有特定于数据库的行话。Laravel 使用 Eloquent ORM 对数据库进行建模。
Laravel 中包含的 Eloquent ORM 提供了一个漂亮、简单的 ActiveRecord 实现来处理你的数据库。每个数据库表都有一个相应的“模型”,用于与该表进行交互。模型允许您查询表中的数据,以及将新记录插入表中。
— Laravel 文档
那么数据库模式定义呢?Laravel 的迁移解决了这个问题。Artisan 有一个迁移命令,可让您定义架构并在以后逐步更新它。让我们为 Product 实体创建一个模型和一个迁移。
$ php artisan make:model Product -m
注意:那里有很多 Artisan 命令,很容易迷路。因此,每个工匠命令都包含一个帮助屏幕,该屏幕显示其他信息,例如可用的选项和参数。要进入帮助页面,命令的名称应该以help
. 运行以下帮助命令以查看该-m
选项代表什么: $ php artisan help make:model
.
这是生成的迁移文件。
数据库/迁移/timestamp_create_products_table.php
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateProductsTable extends Migration { public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('products'); } }
up
在将新表和列迁移到数据库时调用该方法,而在回滚down
迁移时调用该方法。我们为具有三行的表创建了一个模式: id
、created_at
和updated_at
。该$table->timestamps()
方法负责维护created_at
和updated_at
列。让我们在模式定义中再添加几行。
/* Let's add columns for title, description, price, availability */ public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); $table->string('title'); $table->text('description'); $table->integer('price'); $table->boolean('availability'); }); }
我们用四个新列更新了架构。Laravel 的模式构建器支持多种列类型,如string
, text
, integer
,boolean
等。
要执行挂起的迁移,您必须运行以下命令:
php artisan migrate
按照惯例,Laravel 假设Product模型与products表相关联。但是,如果您需要将模型与自定义表名相关联,则可以使用该$table
属性来声明表名。然后该模型将与名为 custom_products的表相关联。
protected $table = 'custom_products';
但我们会保持简单并遵守约定。生成的 Product 模型位于app/目录中。尽管模型类可能看起来是空的,但它配备了各种查询构建器方法,您可以使用这些方法来查询数据库。例如,您可以使用Product::all()
检索所有产品或Product::find(1)
检索 id 为 1 的特定产品。
Laravel 模型具有针对批量分配漏洞的内置保护机制。该 fillable
属性用于声明可以安全地批量分配的属性名称。
应用程序/产品.php
/* Add the fillable property into the Product Model */ protected $fillable = ['title', 'description', 'price', 'availability'];
上面的代码将 、和属性列入白名单title
,并将它们视为可批量分配的。我们现在可以使用该方法将新行插入到 products 表中。 description
price
availability
Product::create
数据库播种
Laravel 允许您使用虚拟数据填充您的开发和生产数据库,然后您可以使用这些数据来测试您的 API 端点。您可以通过执行以下 Artisan 命令来创建种子类。
$ php artisan make:seeder ProductsTableSeeder
生成的种子文件将放置在 database/seeds目录中。
要生成虚拟数据,您可以使用类似 str_random(10)
返回随机字符串的方法。但是如果您需要与实际数据足够接近的数据,您应该使用类似 faker 库的东西。Faker 是一个第三方库,随 Laravel 框架一起提供,用于生成假数据。
数据库/种子/ProductsTableSeeder.php
use App\Product; class ProductsTableSeeder extends Seeder { public function run() { $faker = \Faker\Factory::create(); // Create 50 product records for ($i = 0; $i < 50; $i++) { Product::create([ 'title' => $faker->title, 'description' => $faker->paragraph, 'price' => $faker->randomNumber(2), 'availability' => $faker->boolean(50) ]); } } }
执行db:seed
artisan 命令来填充数据库。
$ php artisan db:seed --class=ProductsTableSeeder
让我们回到routes/api.php并填写缺失的部分。
路线/api.php
/** **Basic Routes for a RESTful service: **Route::get($uri, $callback); **Route::post($uri, $callback); **Route::put($uri, $callback); **Route::delete($uri, $callback); ** */ Route::get('products', function () { return response(Product::all(),200); }); Route::get('products/{product}', function ($productId) { return response(Product::find($productId), 200); }); Route::post('products', function(Request $request) { $resp = Product::create($request->all()); return $resp; }); Route::put('products/{product}', function(Request $request, $productId) { $product = Product::findOrFail($productId); $product->update($request->all()); return $product; }); Route::delete('products/{product}',function($productId) { Product::find($productId)->delete(); return 204; });
控制器
路由文件当前承载路由和处理请求的逻辑。我们可以将请求处理逻辑移到 Controller 类中,以便我们的代码更好地组织和更具可读性。我们先生成一个控制器类。
$ php artisan make:controller ProductsController
Controller 类包含对应于不同 HTTP 操作的各种方法(索引、显示、存储、更新和删除)。我已将请求处理逻辑从路由移至控制器。
app/HTTP/Controllers/ProductsController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Product; class ProductsController extends Controller { public function index() { return Product::all(); } public function show(Product $product) { return $product; } public function store(Request $request) { $product = Product::create($request->all()); return response()->json($product, 201); } public function update(Request $request, Product $product) { $product->update($request->all()); return response()->json($product, 200); } public function delete(Product $product) { $product->delete(); return response()->json(null, 204); } }
路线/api.php
/** **Basic Routes for a RESTful service: **Route::get($uri, $callback); **Route::post($uri, $callback); **Route::put($uri, $callback); **Route::delete($uri, $callback); ** */ Route::get('products', 'ProductsController@index'); Route::get('products/{product}', 'ProductsController@show'); Route::post('products','ProductsController@store'); Route::put('products/{product}','ProductsController@update'); Route::delete('products/{product}', 'ProductsController@delete');
如果您没有注意到,我已经将 Product 实例注入到控制器方法中。这是 Laravel 隐式绑定的一个例子。Laravel 尝试将模型实例名称Product $product
与 URI 段名称匹配{product}
。如果找到匹配项,则将 Product 模型的一个实例注入到控制器操作中。如果数据库没有产品,则返回 404 错误。最终结果与以前相同,但代码更少。
打开 POSTMAN,产品的端点应该可以工作。确保您已 Accept : application/json
启用标题。
验证和异常处理
如果您前往一个不存在的资源,这就是您将看到的。
这NotFoundHTTPException
就是 Laravel 显示 404 错误的方式。如果您希望服务器返回 JSON 响应,则必须更改默认的异常处理行为。Laravel 有一个专门用于异常处理的 Handler 类,位于app/Exceptions/Handler.php。该类主要有两个方法:report()
和render()
。该report
方法用于报告和记录异常事件,而 render 方法用于在遇到异常时返回响应。更新 render 方法以返回 JSON 响应:
应用程序/异常/Handler.php
public function render($request, Exception $exception) { if ($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) { return response()->json([ 'message' => 'Resource not found' ], 404); } return parent::render($request, $exception); }
Laravel 还允许我们使用一组验证规则来验证传入的 HTTP 请求,并在验证失败时自动返回 JSON 响应。验证的逻辑将放置在控制器内。该 Illuminate\Http\Request
对象提供了一个 validate 方法,我们可以使用它来定义验证规则。让我们在 store 方法中添加一些验证检查。
app/HTTP/Controllers/ProductsController.php
public function store(Request $request) { $this->validate($request, [ 'title' => 'required|unique:products|max:255', 'description' => 'required', 'price' => 'integer', 'availability' => 'boolean', ]); $product = Product::create($request->all()); return response()->json($product, 201); }
概括
我们现在有一个适用于产品列表应用程序的 API。但是,该 API 缺乏基本功能,例如身份验证和限制未经授权用户的访问。Laravel 对身份验证具有开箱即用的支持,并且为其构建 API 相对容易。我鼓励您实施身份验证 API 作为练习。
- 为什么选择 Laravel 和 React?
- 路线/api.php
- 数据库/迁移/timestamp_create_products_table.php
- 应用程序/产品.php
- 数据库/种子/ProductsTableSeeder.php
- 路线/api.php
- app/HTTP/Controllers/ProductsController.php
- 路线/api.php
- 应用程序/异常/Handler.php
- app/HTTP/Controllers/ProductsController.php