laravel+react實戰打造企業級高併發分佈式電商小程序(二)
整體使用laravel7+react打造整個電商小程序。裏面會涉及到高併發的知識,mysql的分庫分表,主從讀寫分離的配置,redis集羣的使用,緩存系統的使用,隊列系統的使用等。
先初始化一個laravel的項目。然後配置好.env
文件。
權限管理
既然是電商肯定有後臺,要做權限管理這塊。
先創建表,這裏使用laravel
的migration
。下面是後臺用戶表。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('auth_users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name', 100)->unique();
$table->string('email', 100)->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('auth_users');
}
}
下面是角色表
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRolesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('auth_roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name', 100)->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('auth_roles');
}
}
下面是權限表
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePermissionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('auth_permissions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name',100)->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('auth_permissions');
}
}
下面是用戶角色關聯表
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserRolesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('auth_user_roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id');
$table->bigInteger('role_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('auth_user_roles');
}
}
下面是角色和權限關聯表
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRolePerimissionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('auth_role_permissions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->default(0);
$table->bigInteger('role_id');
$table->bigInteger('perimission_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('auth_role_permissions');
}
}
下面這張是系統錯誤信息表,這裏會返回錯誤信息,這些錯誤信息全部存放在這張表裏。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSysErrorsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sys_errors', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('code',100)->unique()->comment('錯誤編碼');
$table->string('msg')->comment('錯誤信息');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sys_errors');
}
}
創建完這些執行遷移命令就可以了。
php artisan migrate
當然了,在這之前確保你的.env
文件已經配置好了數據庫連接。
我們有了後臺數據還需要一個管理員賬戶,使用seed
填充。
<?php
use App\Models\Auth\UserModel;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run(UserModel $user)
{
$user->name = 'admin';
$user->email = '[email protected]';
$user->password = Hash::make('123456');
$user->save();
}
}
運行填充命令
php artisan db:seed
控制器
這裏我們使用一個laravel
的擴展包,使用composer安裝他
composer require thepatter/query-common
安裝完後查看我的這個文章來使用這個包,根據文章裏面做完之後再回來看下面的內容。
https://blog.csdn.net/Thepatterraining/article/details/105408363
接下來使用artisan
命令創建我們的控制器。
php artisan make:queryController Auth/UserController
創建完之後在創建model
php artisan make:model Models/Auth/UserModel
修改剛纔的Auth/UserModel
,在裏面增加table
屬性。
<?php
namespace App\Models\Auth;
use Illuminate\Database\Eloquent\Model;
class UserModel extends Model
{
//
protected $table = 'auth_users';
}
修改剛纔的Auth/UserController
控制器。
<?php
namespace App\Http\Controllers\Auth;
use QueryCommon\QueryController;
use App\Models\Auth\UserModel;
use App\Models\Auth\UserRoleModel;
class UserController extends QueryController
{
/**
* 字典數組
* ['表裏的字段名' => '字典code',...]
*/
protected $dicArr = [];
/**
* 字段映射 可選,不填默認轉成下劃線格式
* ['搜索字段' => '表字段',...]
*/
protected $filedsAdapter = [];
/**
* 創建時候的字段映射 可選,不填默認轉成下劃線格式
* ['輸入字段' => '表字段']
*/
protected $createAdapter = [
'name' => 'name',
'email' => 'email',
];
//定義表名 格式: table as t
protected $shortTableName;
protected function getModel() {
$this->model = new UserModel;
return $this->model;
}
}
這時候我們對用戶的增刪改查操作就完成了,是不是超級簡單呢。這主要依賴於我們的query-common
擴展包。
我們接下來只需要添加對應的路由就可以了。在routes
下面創建Api/Auth
文件夾。在裏面創建index.php
路由文件。
<?php
use Illuminate\Support\Facades\Route;
Route::prefix('auth')->namespace('Auth')->group(function () {
//後臺創建用戶
Route::post('user', 'UserController@createInfo');
//後臺查詢管理員列表
Route::get('users', 'UserController@queryList');
//後臺更新管理員信息
Route::put('user/{id}', 'UserController@updateInfo');
//後臺刪除管理員
Route::delete('user/{id}', 'UserController@deleteInfo');
});
添加完路由文件後我們需要自動加載路由文件,請看我的這篇文章,路由自動加載。
https://blog.csdn.net/Thepatterraining/article/details/105386868
接下來可以使用postman
來測試了。
獲取用戶列表
其他的就不放圖了。
角色
有了用戶就有角色了,我們的角色表在之前已經創建好了,我們現在同樣的方法創建controller和model。
執行下面的命令。-m
參數是model,這裏指定model後,如果model不存在會自動創建。
php artisan make:queryController Auth/RoleController -m Models/Auth/RoleModel
修改剛纔的Auth/RoleModel
,在裏面增加table
屬性。
<?php
namespace App\Models\Auth;
use Illuminate\Database\Eloquent\Model;
class RoleModel extends Model
{
//
protected $table = 'auth_roles';
}
app/Http/Controllers/Auth/RoleController
文件內容如下
<?php
namespace App\Http\Controllers\Auth;
use QueryCommon\QueryController;
use App\Models\Auth\RoleModel;
class RoleController extends QueryController
{
/**
* 字典數組
* ['表裏的字段名' => '字典code',...]
*/
protected $dicArr = [];
/**
* 字段映射 可選,不填默認轉成下劃線格式
* ['搜索字段' => '表字段',...]
*/
protected $filedsAdapter = [];
/**
* 創建時候的字段映射 可選,不填默認轉成下劃線格式
* ['輸入字段' => '表字段']
*/
protected $createAdapter = [];
//定義表名 格式: table as t
protected $shortTableName;
protected function getModel() {
$this->model = new RoleModel();
return $this->model;
}
}
接着在剛纔的routes/Api/Auth/index
路由文件中增加下面的內容
//後臺查詢角色列表
Route::get('roles', 'RoleController@queryList');
//創建角色
Route::post('role', 'RoleController@createInfo');
//更新角色
Route::put('role/{id}', 'RoleController@updateInfo');
//刪除角色
Route::delete('role/{id}', 'RoleController@deleteInfo');
增加後是下圖這樣
同樣使用postman測試。
用戶和角色關聯
有了用戶和角色就要把這兩個關聯起來了,我們通過在創建用戶和修改用戶的時候關聯角色,在這時候就要更改之前的Auth/UserController
了。
增加下面的函數。
/**
* 創建完用戶後執行的操作
*/
protected function createAfter($id) {
$this->userRole($id);
}
//更新完主表之後可以進行的操作
protected function updateAfter($id) {
//更新完用戶信息需要更新用戶角色關聯
//先刪除所有關聯,再重新創建
UserRoleModel::where('user_id', $id)->delete();
$this->userRole($id);
}
/**
* 用戶角色操作,先刪除用戶的所有角色,再創建角色關聯
* @param int $id 用戶id
*/
private function userRole($id) {
$ids = $this->request->input('roleIds');
//組織數據
$insertDatas = [];
foreach ($ids as $roleId) {
$insertData = [];
$insertData['user_id'] = $id;
$insertData['role_id'] = $roleId;
$insertData['created_at'] = date('Y-m-d H:i:s');
$insertDatas[] = $insertData;
}
//一次性插入
UserRoleModel::insert($insertDatas);
}
createAfter
方法是在創建完用戶後執行的,updateAfter
方法是更新完用戶信息後執行的。傳入用戶id。我們在這裏刪除之前的用戶和角色關聯,把新的循環添加到數組中,一次性插入數據庫。因爲循環插入會進行多次數據庫io
操作,而數據庫io是比較耗費資源和時間的,所以我們儘可能少進行數據庫操作。
在創建和更新時候我們還需要驗證參數,我們再添加下面的方法。
/**
* 在創建之前調用,用來驗證參數
*/
protected function createBefore() {
//檢測頁碼和每頁數量
$rules = [
'name' => 'required|unique:auth_users,name',
'email' => 'required|email|unique:auth_users,email',
'password' => 'required',
'roleIds' => 'required|array',
];
$messages = [
'name.required' => '用戶名爲必填項',
'name.unique' => '用戶已經存在',
'email.required' => '郵箱爲必填項',
'email.unique' => '郵箱已經存在',
'email.email' => '請輸入正確的郵箱格式',
'password.required' => '密碼爲必填項',
'roleIds.required' => '角色爲必填項',
'roleIds.array' => '角色必須是數組類型',
];
$this->valid($rules, $messages);
//判斷角色數組是不是在數據庫都存在
$roleNum = RoleModel::whereIn('id', $this->request->roleIds)->count();
if ($roleNum != count($this->request->roleIds)) {
//角色id不對
throw new CommonException(ErrorModel::ROLE_NOT_FOUND);
}
}
/**
* 在創建之前調用,用來驗證參數
*/
protected function updateBefore() {
//檢測頁碼和每頁數量
$rules = [
'name' => 'required',
'email' => 'required|email',
'roleIds' => 'required|array',
];
$messages = [
'name.required' => '用戶名爲必填項',
'email.required' => '郵箱爲必填項',
'email.email' => '請輸入正確的郵箱格式',
'roleIds.required' => '角色爲必填項',
'roleIds.array' => '角色必須是數組類型',
];
$this->valid($rules, $messages);
//判斷角色數組是不是在數據庫都存在
$roleNum = RoleModel::whereIn('id', $this->request->roleIds)->count();
if ($roleNum != count($this->request->roleIds)) {
//角色id不對
throw new CommonException(ErrorModel::ROLE_NOT_FOUND);
}
}
createBefore
方法在創建用戶之前調用,updateBefore
方法在更新之前調用,用來驗證參數信息。驗證角色在數據庫中不存在後要返回錯誤,直接throw拋出異常即可,因爲在外部已經用try catch
捕獲了,這裏返回的是一個error code
,在Sys/ErrorModel
中定義一個錯誤信息。爲了方便管理,所有的錯誤以常量的方式定義在errorModel裏面。真正的錯誤信息在我們一開始創建的sys_error
數據表中。我們在數據表中添加一條錯誤信息,code
是100002的,msg
是角色未定義!
const ROLE_NOT_FOUND = '100002'; //角色未定義!
我們可以傳一些錯誤的角色id給到接口中,使用postman來測試一下。因爲這個用戶已經創建了,所以返回了用戶已經存在的錯誤信息。
權限
我們使用同樣的方式創建權限的controller
和model
。
php artisan make:queryController Auth/PermissionController -m Models/Auth/PermissionModel
和上面一樣,修改剛纔的Auth/PermissionModel
,在裏面增加table
屬性。後面的就不再說這裏了。
<?php
namespace App\Models\Auth;
use Illuminate\Database\Eloquent\Model;
class PermissionModel extends Model
{
//
protected $table = 'auth_permissions';
}
增加路由。
//後臺查詢權限列表
Route::get('permissions', 'PermissionController@queryList');
//創建權限
Route::post('permission', 'PermissionController@createInfo');
//更新權限
Route::put('permission/{id}', 'PermissionController@updateInfo');
//刪除權限
Route::delete('permission/{id}', 'PermissionController@deleteInfo');
使用postman測試。
現在呢,我們權限管理的後端接口就算做完了,當然了,後面還會根據需要調整。