Lumen API開發(fā)
Laravel和Lumen的區(qū)別:Lumen輕量級框架对扶,集合了Laravel的優(yōu)美語法执庐,支持
ORM
沒有Blade
模板引擎,我個人覺得這個框架適用于API
的開發(fā)虏冻,對于相比Laravel
性能槽棍,如果Lumen
打開了門面
就缺失了它自己的特性,就和Laravel
沒什么區(qū)別了汽纠。
安裝Lumen
- 安裝Composer
cd /usr/local/bin
php -r“copy('https://getcomposer.org/installer'卫键,'composer-setup.php');”
php -r“if(hash_file('SHA384','composer-setup.php')==='544e09ee996cdf60ece3804abc52599c22f1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061'){echo'Installer verified';} else {echo'Installer corrupt'; unlink('composer-setup虱朵。 php');} echo PHP_EOL;“
php composer-setup.php
php -r“unlink('composer-setup.php');”
composer --version 或 composer -v // 查看是否安裝成功莉炉?
- Mac配置Path路徑
sudo vim ~/.bash_profile
export PATH=~/.composer/vendor/bin:$PATH // 黏貼這段代碼
執(zhí)行source ~/.bash_profile // 更新配置文件
- 安裝Lumen項目(兩種方式)
第一種方式:通過 Lumen 安裝器 (不支持選擇版本默認最新的)
【幫助】lumen help new
【Lumen】lumen new project // 直接new一個項目就可以了
第二種方式:Composer 安裝(速度慢但可指定安裝版本)
【安裝指定版本】composer create-project laravel/lumen Lumen-5.5 --prefer-dist "5.5.*"
// 目前只有通過 composer create-project 方式支持選擇版本, lumen new 方式不支持碴犬。
配置完域名直接訪問Lumen
添加缺失的Artisan命令
執(zhí)行
php artisan list
會發(fā)現(xiàn)絮宁,Lumen
相比Laravel
缺失了一部分make···
等命令,像我這種懶人必須得想辦法解決 gitHub:lumen-generators
- 執(zhí)行Composer安裝
composer require wn/lumen-generators
- 注冊服務提供者Providers
// 在app/Providers/AppServiceProvider.php
public function register()
{
if ($this->app->environment() == 'local') {
$this->app->register('Wn\Generators\CommandsServiceProvider');
}
}
- 展示渲染Providers
// 在bootstrap/app.php找到Register Service Providers添加下面代碼
$app->register(Wn\Generators\CommandsServiceProvider::class);
- 查看命令
php artisan list
wn-artisan.png -
修改Controller和Model模板源碼(不改你會后悔的7)
templates-path.png
控制器模板:
<?php
namespace App\Http\Controllers\{{name}};
use Laravel\Lumen\Routing\Controller;
class {{name}} extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @author
*/
public function index()
{
//
}
}
model 模板:
<?php
namespace {{namespace}}\Models;
use Illuminate\Database\Eloquent\Model;
class {{name}} extends Model {
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [];
}
- wn配置完的artisan操作命令
// 有個bug需要自己去控制器里再編輯下名稱绍昂,著急開發(fā)懶得去翻源碼了
【生成控制器】php artisan wn:controller Static/Static
開啟Lumen的各種擴展必須組件 (門面操作,謹慎開啟)
// 開啟 Eloquent
$app->withEloquent();
// 開啟 Session
去掉 $app->middleware(); 的 StartSession 中間件的注釋
// 開啟 路由中間件
去掉 routeMiddleware 的注釋
// 配置 數(shù)據(jù)庫 偿荷,復制 /config文件
去源碼vendor/laravel/lumen-framework/config 復制到根目錄下
- 對于Lumen的dd打印
什么窘游?哦,上帝跳纳!真是見鬼张峰!怎么會有人在 Laravel 中還在用 echo + die() ?好家伙棒旗,我敢打賭喘批,他一定沒有好好看文檔,我向圣母瑪利亞保證铣揉。如果讓我看到這群愚蠢的土撥鼠饶深,看在上帝的份上,我會用靴子狠狠地踢他們的屁股逛拱,我發(fā)誓我絕對會敌厘。
(來自一個逗比的Lumendd()
打印解釋)
// 安裝 dd() 打印樣式組件
composer require symfony/var-dumper
微信小程序【第三方平臺賬號登錄流程圖】
圖片來源PHP中文網(wǎng):圖片中的
3rd_session
類似于Auth2
的認證_token
,所以后端需要寫有狀態(tài)的接口時每次驗證這個值(是否過期朽合,是否正確)自己封裝一個繼承類去驗證俱两,請看下面代碼。
- 小程序繼承類代碼:
<?php
namespace App\Http\Controllers\Applets;
use App\Http\Controllers\Controller;
use App\Traits\AppletsTrait;
/**
* 小程序獲取token基類認證
*
* Class BasisController
* @package App\Http\Controllers\Applets
* @author SuperHao - 619596123@qq.com
*/
class BasisController extends Controller
{
use AppletsTrait;
protected $session3rd;
/**
* BasisController constructor.
* @author SuperHao - 619596123@qq.com
*/
public function __construct()
{
$this->getSession3rd($session3rd);
$this->session3rd = $session3rd;
}
}
- 小程序
Trait
的getSession3rd
方法:
/**
* 獲取session3rd參數(shù)
*
* @return boolean
* @author SuperHao - 619596123@qq.com
*/
public function getSession3rd(&$session3rd)
{
$result = array_key_exists('HTTP_SESSION3RD', $_SERVER);
if (!$result) return false;
$session3rd = $_SERVER['HTTP_SESSION3RD'];
return true;
}
- 繼承基類控制器里使用:
<?php
namespace App\Http\Controllers\Applets;
use Illuminate\Http\Request;
class TestController extends BasisController
{
/**
* Display a listing of the resource
*
* @throws \Exception
* @author SuperHao - 619596123@qq.com
*/
public function index()
{
// 獲取 Session3rd (這里直接使用基類的參數(shù))
$session3rd = $this->session3rd;
// 獲取 redis 里的用戶信息
$userInfo = cache($session3rd);
// 數(shù)據(jù)打印
// array:3 [
// "session_key" => "2C7rPDnhXAy5dUAdpS==..."
// "openid" => "odLil5N4yHjt2nUZfnjuIGmca..."
// "unionid" => "oKMyGwZjvi0WigertI0XWOP2..."
// ]
dd($userInfo);
}
}
- 中間件攔截基類Controller代碼:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Cache;
class AppletsTokenMiddleware
{
/**
* 獲取請求頭Session3rd.
*
* @param $request
* @param Closure $next
* @return \Illuminate\Http\JsonResponse|mixed
* @author SuperHao - 619596123@qq.com
*/
public function handle($request, Closure $next)
{
$result = array_key_exists('HTTP_SESSION3RD', $_SERVER);;
if ($result) {
if (Cache::has($_SERVER['HTTP_SESSION3RD'])) return $next($request);
}
return response()->json(['status' => false, 'code' => 401, 'message' => '賬戶過期曹步,請重新授權登陸']);
}
}
小程序后端登錄憑證校驗:
小程序接口官網(wǎng)地址宪彩,找到登陸憑證,里面的
wx.login
是前端的讲婚,后臺不用管尿孔。(前提是必須了解上面的流程圖)
然后找到登錄憑證校驗
這個接口上面寫的很詳細,好像沒有說是異步還是同步
,但是網(wǎng)頁打開調用了一下你會發(fā)現(xiàn)這是個同步的
接口(同步的接口就是發(fā)送參數(shù)后微信立馬回調給你參數(shù)活合,異步的話則需要配置回調域名并且還得打印寫入到日志或者文件中才能調試參數(shù))下面貼一下代碼demo:
- 微信接口工具類
<?php
namespace App\Tools;
/**
* 微信接口工具類
*
* Class WeChatTool
* @package App\Tools
* @author SuperHao - 619596123@qq.com
*/
class WeChatTool
{
const OK = 0; // success
const IllegalAesKey = -41001; // encodingAesKey 非法
const IllegalIv = -41002; // appId missing (缺少appId參數(shù))
const IllegalBuffer = -41003; // aes 解密失敗
const DecodeBase64Error = -41004; // 解密后得到的buffer非法
/**
* 返回轉譯 constCodeMessage
*
* @param $code
* @return string
* @author SuperHao - 619596123@qq.com
*/
static public function constCodeMsg($code)
{
switch ($code) {
case 0:
return 'success';
break;
case -41001:
return 'encodingAesKey 非法';
break;
case -41002:
return 'appId missing (缺少appId參數(shù))';
break;
case -41003:
return 'aes 解密失敗';
break;
case -41004:
return '解密后得到的buffer非法';
break;
default:
return '未知解密錯誤';
break;
}
}
/**
* 獲取168位的隨機字符串
*
* @return string
* @author SuperHao - 619596123@qq.com
*/
static public function getSession3rd()
{
/**
* 微信的官方文檔推薦用這種操作系統(tǒng)提供真正隨機數(shù)的方法
* /dev/urandom 和 /dev/random 已經(jīng)算是很接近真隨機數(shù)的隨機數(shù)了
*/
return shell_exec('head -n 80 /dev/urandom | tr -dc A-Za-z0-9 | head -c 168');
}
/**
* 微信接口報錯code
*
* @param $code
* @return array|\Illuminate\Contracts\Translation\Translator|null|string
* @author SuperHao - 619596123@qq.com
*/
static public function codeErrorMessage($code)
{
/**
* 判斷是否是類型中的
*/
if (array_key_exists($code, trans('applets'))) {
$message = $code . ': ' . trans('applets.' . $code);
} else {
// 未知錯誤
$message = $code . ': ' . trans('applets.unknown');
}
return $message;
}
/**
* 解密微信數(shù)據(jù). (檢驗數(shù)據(jù)的真實性雏婶,并且獲取解密后的明文)
*
* @param $sessionKey string session_key
* @param $encryptedData string 加密的用戶數(shù)據(jù)
* @param $iv string 與用戶數(shù)據(jù)一同返回的初始向量
* @param $data array 解密后的原文
* @return array
* @author SuperHao - 619596123@qq.com
*/
static public function decryptData($sessionKey, $encryptedData, $iv, &$data)
{
if (strlen($sessionKey) != 24) {
return ['status' => false, 'code' => self::IllegalAesKey, 'message' => self::constCodeMsg(self::IllegalAesKey)];
}
$aesKey = base64_decode($sessionKey);
if (strlen($iv) != 24) {
return ['status' => false, 'code' => self::IllegalIv, 'message' => self::constCodeMsg(self::IllegalIv)];
}
$aesIV = base64_decode($iv);
$aesCipher = base64_decode($encryptedData);
$result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
$dataObj = json_decode($result);
if ($dataObj == NULL) {
return ['status' => false, 'code' => self::IllegalBuffer, 'message' => self::constCodeMsg(self::IllegalBuffer)];
}
if ($dataObj->watermark->appid != config('applets.appId')) {
return ['status' => false, 'code' => self::IllegalBuffer, 'message' => self::constCodeMsg(self::IllegalBuffer)];
}
$data = $result;
return ['status' => true, 'code' => self::OK, 'message' => self::constCodeMsg(self::OK)];
}
}
- 微信登錄獲取Code處理代碼
// 前端傳輸code換取sessionkey (get code2Session).
public function index(Request $request)
{
/**
* 驗證登陸信息
*/
$validator = Validator::make($request->all(), [
'js_code' => 'required|alpha_dash',
]);
if ($validator->fails()) {
return $this->response->error($validator->errors()->first());
}
$jsCode = $request->input('js_code');
/**
* getJsCode
*/
$url = sprintf(config('applets.url.getJsCode'), config('applets.appId'), config('applets.appSecret'), $jsCode);
/**
* send Http
*/
$result = CurlTool::httpsRequest($url);
$result = json_decode($result, true);
/**
* Exists WeChat Error
*/
if (array_key_exists('errcode', $result)) {
/**
* 微信接口報錯代碼轉譯
*/
$message = WeChatTool::codeErrorMessage($result['errcode']);
return $this->response->error($message);
}
return $this->response->success($result);
}
- 微信登錄解密數(shù)據(jù)代碼
public function store(LoginStoreRequest $request)
{
$json = $request->input('json');
$sessionKey = $request->input('session_key');
/**
* 解密數(shù)據(jù)
*/
$result = WeChatTool::decryptData($sessionKey, $json['encryptedData'], $json['iv'], $data);
if (!$result['status']) {
$data = [
'session_key' => $sessionKey,
'json' => $json,
];
filePutData('storage/wechat.log', $data);
$message = $result['code'] . ':' . $result['message'];
return $this->response->error($message);
}
/**
* 檢測過濾微信數(shù)據(jù)是否存在
*/
$data = json_decode($data, true);
if (!array_key_exists('openId', $data) && !array_key_exists('unionId', $data)) {
return $this->response->error(trans('request.arrayKeyExists'));
}
/**
* build
*/
$build = [
'nickname' => $data['nickName'],
'gender' => $data['gender'],
'openid' => $data['openId'],
'unionid' => $data['unionId'],
'avatarUrl' => $data['avatarUrl'],
'country' => $data['country'],
'province' => $data['province'],
'city' => $data['city'],
'language' => $data['language'],
];
/**
* 判斷是否創(chuàng)建授權過
*/
$weChatUser = $this->wechatUser->where(['unionid' => $data['unionId']])->first();
if (!empty($weChatUser)) {
/**
* save userInfo
*/
$weChatUser->save($build);
$data['wechat_id'] = $weChatUser->id;
} else {
/**
* create weChatUser Data
*/
$create = $this->wechatUser->create($build);
$data['wechat_id'] = $create->id;
}
/**
* 獲取 3rd_session (168位的隨機字符串)
*/
$response = [
'unionid' => $data['unionId'],
'Authorization' => 'Bearer ' . WeChatTool::getSession3rd(), // session3rd
];
// 編寫redis值
$session3rdRedis = session3rd($response['Authorization']);
/**
* Redis 儲存微信用戶信息
*/
Cache::remember($session3rdRedis, config('applets.cacheSession3rd'), function () use ($data) {
return [
'wechat_id' => $data['wechat_id'],
'unionId' => $data['unionId'],
'openId' => $data['openId'],
'nickName' => $data['nickName'],
'avatarUrl' => $data['avatarUrl'],
'gender' => $data['gender'],
];
});
return $this->response->created(trans('response.decryptData'), $response);
}
小程序調試必備:
- Sunny-Ngrok
Sunny-Ngrok內網(wǎng)穿透工具,是一個很簡單還
不收費
的軟件白指。里面有體驗隧道留晚,用這個足夠了。具體使用教程官方有詳細的視頻介紹
- Wampserver (或者可以使用
Vagrant
自帶的網(wǎng)絡配置public_network
)
為什么推薦這個告嘲?因為每次都得開本地
Vagrant
虛擬機才能訪問倔丈,如果寫前后臺分離為了和前端人員調試方便,開啟Wampserver
直接指向自己的Vagrant
目錄訪問自己的Api
會更方便別人状蜗,即便是平時自己的Vagrant
不啟動前端也可以訪問接口需五。
1.配置局域網(wǎng)訪問
Win +R 打開 Cmd 輸入 ipconfig 查看自己的以太網(wǎng)局域網(wǎng)IPv4
打開 httpd-vhosts 找到 Require local 替換成 Require all granted
如下:
<VirtualHost *:80>
ServerName 192.168.10.72
DocumentRoot D:/Vagrant/
<Directory "D:/Vagrant/">
Options +Indexes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# 借鑒地址:
// https://jingyan.baidu.com/article/acf728fd556c93f8e410a344.html
注意:
記得去自己的網(wǎng)絡里查看是否是固定的以太網(wǎng) IPv4
,如果不是請如下設置:
IP地址:192.168.10.110
子網(wǎng)掩碼:255.255.255.0
默認網(wǎng)關:192.168.10.1 //里面的10 是自己公司的網(wǎng)段
DNS:
首選DNS服務器:114.114.114.114
備用DNS服務器:8.8.8.8
2.配置 Wampserver 的 Redis
雖然你的vagrant裝了redis轧坎,但是Wampserver 是沒有的宏邮,所以需要裝一下php擴展,找了半天找到靠譜的:CSDN-Wampserver安裝redis擴展缸血,我就不搬過來了蜜氨。
但是總不能一直開著cmd
運行窗,太累太low -> Windows下Redis一直后臺運行
- 到Redis目錄下 安裝redis服務:
redis-server --service-install redis.windows.conf --loglevel verbose
# 提示(Redis已成功安裝為服務) :
[13808] 20 Sep 15:04:30.063 # Granting read/write access to 'NT AUTHORITY\NetworkService' on: "D:\Redis" "D:\Redis\"
[13808] 20 Sep 15:04:30.064 # Redis successfully installed as a service.
- 啟動Redis:redis-server --service-start 關閉 -stop
- Laravel 【laravel-sql-logger】記錄框架中的SQL查詢
一個很好用的
Laravel
sql 記錄日志捎泻,它的功能大體有:
1.
記錄框架中的所有執(zhí)行過的SQL
2.
展示每條執(zhí)行速度飒炎,用來分析SQL
的問題,默認情況下以毫秒為單位
3.
可以日志記錄慢查詢SQL
(也以毫秒為單位笆豁,可設置慢查詢時間)
composer require mnabialek/laravel-sql-logger --dev
- 執(zhí)行擴展包資源選擇對應數(shù)字服務類
php artisan vendor:publish
- 組件配置文件路徑在:
config/sql_logger.php
Laravel-模型關聯(lián)-遠程一對多(特殊需求)
有個需求郎汪,需要遠程查表。用的模型關聯(lián)所以嘗試了期待已久的
遠程一對多
闯狱,問題就是參數(shù)有點亂煞赢,官方也沒有詳細的講解。所以親自試了好久哄孤,總結寫出以下注釋:
情況說明:(現(xiàn)在有3張表)
1是主表(文章詳情表) 2是中間表(評論表) 3是遠程表(評論人的user表)
id,comment_id id,user_id id,name
需求:1想拿到評論他文章的用戶名稱照筑,也就是3表的username
/**
* 文章查詢評論人信息
* 遠程一對多
*/
public function commentUser()
{
return $this->hasManyThrough(
1 'App\Applets\user', // 遠程表
2 'App\Applets\comment', // 中間表
3 'id', // 中間表對主表的關聯(lián)字段(2.id)
4 'id', // 遠程表對中間表的關聯(lián)字段(3.id)
5 'comment_id', // 主表對中間表的關聯(lián)字段(1.comment_id)
6 'user_id' // 中間表對遠程表的關聯(lián)字段(2.user_id)
);
}
* 如果把參數(shù)分為 1、2瘦陈、3凝危、4、5晨逝、6 就是:
* 1 和 2 對應
* 3 和 5 對應
* 4 和 6 對應
借著上面的分析順道說一下別的模型關聯(lián)參數(shù):
(參數(shù)都是數(shù)字代表蛾默,有時候也可不填參數(shù),Laravel 會根據(jù)規(guī)則自己找關聯(lián))
【hasOne】 一對一 1關聯(lián)模型 2關聯(lián)表的關聯(lián)字段 3自己主表的id
【hasMany】 一對多 1關聯(lián)模型 2關聯(lián)表的關聯(lián)字段 3自己主表的id
【belongsTo】 反向一對一(多) 1關聯(lián)表 2主表關聯(lián)的關聯(lián)表ID 3關聯(lián)表ID
如果有什么不太清楚咏花,或者我寫的不好的趴生。請留言評論,隨時都回復哈昏翰,謝謝