小程序Lumen API开发

Lumen API开发

小程序Lumen API开发_第1张图片
Lumen.png

Laravel和Lumen的区别:Lumen轻量级框架,集合了Laravel的优美语法,支持ORM没有Blade模板引擎,我个人觉得这个框架适用于API的开发,对于相比Laravel性能,如果Lumen打开了门面就缺失了它自己的特性,就和Laravel没什么区别了。

安装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  // 黏贴这段代码
执行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

小程序Lumen API开发_第2张图片
Lumen-5.5.png

添加缺失的Artisan命令

执行php artisan list会发现,Lumen相比Laravel缺失了一部分make···等命令,像我这种懒人必须得想办法解决 gitHub:lumen-generators

小程序Lumen API开发_第3张图片
not have-artisan.jpg
  • 执行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
    小程序Lumen API开发_第4张图片
    wn-artisan.png
  • 修改Controller和Model模板源码(不改你会后悔的!)


    小程序Lumen API开发_第5张图片
    templates-path.png

    控制器模板:

model 模板:

  • wn配置完的artisan操作命令
// 有个bug需要自己去控制器里再编辑下名称,着急开发懒得去翻源码了
【生成控制器】php artisan wn:controller Static/Static

开启Lumen的各种扩展必须组件 (门面操作,谨慎开启)

// 开启 Eloquent
$app->withEloquent();
// 开启 Session
去掉 $app->middleware(); 的 StartSession 中间件的注释
// 开启 路由中间件
去掉 routeMiddleware 的注释
// 配置 数据库 ,复制 /config文件
去源码vendor/laravel/lumen-framework/config 复制到根目录下
  • 对于Lumen的dd打印

什么?哦,上帝!真是见鬼!怎么会有人在 Laravel 中还在用 echo + die() ?好家伙,我敢打赌,他一定没有好好看文档,我向圣母玛利亚保证。如果让我看到这群愚蠢的土拨鼠,看在上帝的份上,我会用靴子狠狠地踢他们的屁股,我发誓我绝对会。 (来自一个逗比的Lumen dd() 打印解释)

// 安装 dd() 打印样式组件
composer require symfony/var-dumper

微信小程序【第三方平台账号登录流程图】

小程序Lumen API开发_第6张图片
微信授权登录流程图.png

图片来源PHP中文网:图片中的3rd_session类似于Auth2的认证_token,所以后端需要写有状态的接口时每次验证这个值(是否过期,是否正确)自己封装一个继承类去验证,请看下面代码。

  • 小程序继承类代码:
getSession3rd($session3rd);
        $this->session3rd = $session3rd;
    }
}
  • 小程序 TraitgetSession3rd 方法:
/**
 * 获取session3rd参数
 *
 * @return boolean
 * @author SuperHao - [email protected]
 */
 public function getSession3rd(&$session3rd)
 {
     $result = array_key_exists('HTTP_SESSION3RD', $_SERVER);
     if (!$result) return false;
     $session3rd = $_SERVER['HTTP_SESSION3RD'];
     return true;
 }
  • 继承基类控制器里使用:
session3rd;

        // 获取 redis 里的用户信息
        $userInfo = cache($session3rd);
        
        // 数据打印
        // array:3 [
        //   "session_key" => "2C7rPDnhXAy5dUAdpS==..."
        //   "openid" => "odLil5N4yHjt2nUZfnjuIGmca..."
        //   "unionid" => "oKMyGwZjvi0WigertI0XWOP2..."
        // ]
        dd($userInfo);
    }
}
  • 中间件拦截基类Controller代码:
json(['status' => false, 'code' => 401, 'message' => '账户过期,请重新授权登陆']);
    }
}
小程序后端登录凭证校验:

小程序接口官网地址,找到登陆凭证,里面的wx.login是前端的,后台不用管。(前提是必须了解上面的流程图)
然后找到 登录凭证校验 这个接口上面写的很详细,好像没有说是异步还是同步,但是网页打开调用了一下你会发现这是个同步的接口(同步的接口就是发送参数后微信立马回调给你参数,异步的话则需要配置回调域名并且还得打印写入到日志或者文件中才能调试参数)下面贴一下代码demo:

  • 微信接口工具类
 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);
}
  • 微信登录解密数据代码
public function store(LoginStoreRequest $request)
{
    $json = $request->input('json');
    $sessionKey = $request->input('session_key');

    /**
     * 解密数据
     */
    $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);
    }

    /**
     * 检测过滤微信数据是否存在
     */
    $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'],
    ];

    /**
     * 判断是否创建授权过
     */
    $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内网穿透工具,是一个很简单还不收费的软件。里面有体验隧道,用这个足够了。具体使用教程官方有详细的视频介绍

  • Wampserver (或者可以使用 Vagrant 自带的网络配置 public_network)

为什么推荐这个?因为每次都得开本地Vagrant虚拟机才能访问,如果写前后台分离为了和前端人员调试方便,开启Wampserver直接指向自己的Vagrant目录访问自己的Api会更方便别人,即便是平时自己的Vagrant不启动前端也可以访问接口。

1.配置局域网访问

Win +R 打开 Cmd 输入 ipconfig 查看自己的以太网局域网IPv4
小程序Lumen API开发_第7张图片
ipconfig.png
打开 httpd-vhosts 找到 Require local 替换成 Require all granted
如下:

    ServerName 192.168.10.72
    DocumentRoot D:/Vagrant/
    
        Options +Indexes +FollowSymLinks +MultiViews
        AllowOverride All
        Require all granted
    

# 借鉴地址:
// https://jingyan.baidu.com/article/acf728fd556c93f8e410a344.html

注意:记得去自己的网络里查看是否是固定的 以太网 IPv4,如果不是请如下设置:

IP地址:192.168.10.110
子网掩码:255.255.255.0
默认网关:192.168.10.1  //里面的10 是自己公司的网段

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. 记录框架中的所有执行过的SQL
2. 展示每条执行速度,用来分析SQL的问题,默认情况下以毫秒为单位
3. 可以日志记录慢查询SQL (也以毫秒为单位,可设置慢查询时间)

composer require mnabialek/laravel-sql-logger --dev
  • 执行扩展包资源选择对应数字服务类
php artisan vendor:publish
  • 组件配置文件路径在:config/sql_logger.php
Laravel-模型关联-远程一对多(特殊需求)

有个需求,需要远程查表。用的模型关联所以尝试了期待已久的 远程一对多,问题就是参数有点乱,官方也没有详细的讲解。所以亲自试了好久,总结写出以下注释:

情况说明:(现在有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',                   // 中间表对主表的关联字段(2.id)
      4   'id',                   // 远程表对中间表的关联字段(3.id)
      5   'comment_id',           // 主表对中间表的关联字段(1.comment_id)
      6   'user_id'               // 中间表对远程表的关联字段(2.user_id)
     );
 }

* 如果把参数分为 1、2、3、4、5、6 就是:
* 1 和 2 对应
* 3 和 5 对应
* 4 和 6 对应

借着上面的分析顺道说一下别的模型关联参数:
(参数都是数字代表,有时候也可不填参数,Laravel 会根据规则自己找关联)
【hasOne】    一对一            1关联模型  2关联表的关联字段     3自己主表的id
【hasMany】   一对多            1关联模型  2关联表的关联字段     3自己主表的id
【belongsTo】 反向一对一(多)   1关联表    2主表关联的关联表ID   3关联表ID

如果有什么不太清楚,或者我写的不好的。请留言评论,随时都回复哈,谢谢

你可能感兴趣的:(小程序Lumen API开发)