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
变量并在$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
以 查看所有可用的artisan命令。
配置环境
您的应用程序的根目录中将包含一个.env文件。 在此声明所有特定于环境的配置信息。 如果尚未为您的应用程序创建数据库,则将数据库详细信息添加到.env文件中。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sampledb
DB_USERNAME=root
DB_PASSWORD=
了解模型,路线和控制器
Laravel是遵循模型-视图-控制器(MVC)架构的框架。 广义地说,MVC可帮助您将数据库查询(模型)与与如何处理请求(控制器)以及如何呈现布局(视图)有关的逻辑分开。 下图演示了典型的Laravel应用程序的工作。
由于我们正在使用Laravel构建API,因此我们的讨论将仅限于模型和控制器。 我们将在本教程的第二部分中查看用于创建视图的选项。
路由器
当服务器收到HTTP请求时,Laravel尝试将其与在任何路由文件中注册的路由进行匹配。 所有路由文件都位于路由目录内。 route / web.php承载Web界面的路由 ,而route / api.php承载API的路由。 在api.php中注册的路由将以/api
为前缀(与localhost:3000 / api相同)。 如果需要更改此行为,则应转到RouteServiceProvider
中的RouteServiceProvider
类, 然后在此处进行更改。
由于我们正在构建产品列表应用程序,因此这里是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方法请求服务器在给定资源上执行所需的操作。
路由器允许您声明资源的路由以及针对该资源的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之类的工具。
产品型号
产品资源需要一个可以与数据库交互的模型。 模型是位于数据库顶部的层,隐藏了所有特定于数据库的术语。 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
属性声明$table
的名称。 然后,该模型将与名为custom_products的表相关联。
protected $table = 'custom_products';
但是,我们将使事情变得简单,并遵循惯例。 生成的产品模型位于app /目录中。 尽管模型类似乎是空的,但它配备了各种查询构建器方法,可用于查询数据库。 例如,您可以使用Product::all()
检索所有产品,或使用Product::find(1)
检索ID为1的特定产品。
Laravel模型具有针对大规模分配漏洞的内置保护机制。 fillable
属性用于声明可以安全地批量分配的属性名称。
app / Product.php
/* Add the fillable property into the Product Model */
protected $fillable = ['title', 'description', 'price', 'availability'];
上面的代码将title
, description
, price
和availability
属性列入白名单,并将其视为可批量分配。 现在,我们可以使用Product::create
方法将新行插入products表中。
数据库播种
Laravel使您可以使用虚拟数据填充开发和生产数据库,然后可以使用这些虚拟数据来测试API端点。 您可以通过执行以下Artisan命令来创建种子类。
$ php artisan make:seeder ProductsTableSeeder
生成的种子文件将放置在database / seeds目录中。
要生成虚拟数据,可以使用诸如str_random(10)
返回随机字符串的东西。 但是,如果您需要的数据与实际数据足够接近,则应使用伪造者库之类的东西。 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在app / Exceptions / Handler.php中有一个专门用于异常处理的Handler类。 该类主要有两个方法: report()
和render()
。 report
方法对于报告和记录异常事件很有用,而render方法用于在遇到异常时返回响应。 更新render方法以返回JSON响应:
app / Exceptions / 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
对象提供了一种验证方法,我们可以使用该方法来定义验证规则。 让我们向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或希望通过扩展来扩展您的知识,网站或应用程序的人,我们可以在Envato Market上进行各种研究。
现在我们已经完成了后端的工作,我们将把重点转移到前端概念上。 请继续关注本系列的第二部分。 在评论区分享你的观点。