作者

一、项目简介

本次项目在使用Laravel5.7的基础上结合微信小程序实现一个无人货架的售卖系统。具体的技术逻辑如下: 1、后端接口认证使用Jwt-auth,通过接口认证拿到用户id。参考文档:https://github.com/tymondesigns/jwt-auth/wiki/Installation 2、前端小程序支付使用的是easyWeChat第三方包。参考文档:https://www.easywechat.com/docs/4.0/mini-program/app_code https://github.com/overtrue/laravel-wechat 3、微信小程序参考文档:https://developers.weixin.qq.com/miniprogram/dev/api/

二、项目开发----接口认证

1、使用Laravel框架写一个简易后台,包含的模块有:货架管理、商品管理、广告管理,实现基本增删改查即可。 2、写接口,写好前端所需要的全部接口,并在apizza上进行测试。包含的接口有:前端首页、加入购物车、购物车列表、购物车数量增减、清空购物车(全部和单条),接口测试时,用户的id暂时随意定义即可。 3、使用Jwt-auth把购物车用户id变活。Jwt-ath安装配置具体步骤如下: (1)、在composer.json中的require中添加如下代码,进入项目终端,执行 composer update命令。

"require": {
"tymon/jwt-auth": "0.5.*"
}

(2)、在config/app.php中注册服务和门面

providers   Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
aliases     'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,

(3)、生成配置文件:php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider" (4)、生成秘钥:php artisan jwt:generate,此时会报错:

Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist

解决方法:vendor/tymon/jwt-auth/src/Commands/JWTGenerateCommand.php 最后一行加上

public function handle()
{
   $this->fire();
}

然后再执行:php artisan jwt:generate,你会看到:jwt-auth secret [zwIX0fG2Q9UUnOy7vLUmNYRLUiu90VjE] set successfully

(5)、在api.php中写上路由: $this->any('/auth', 'MiniController@auth'); 创建生成token的控制器MiniController,里面写上

public function auth()
{
    //生成token
    $user = User::first();
    $token = JWTAuth::fromUser($user);
    return response()->json(compact('token'));
}

(6)、在Kernel.php文件中注册Jwt自带的路由中间件,同时在api.php中使用路由中间件:

protected $routeMiddleware = [
    ****
    'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
    'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
];

postman 访问接口地址:http://127.0.0.1:8000/api/auth,请求选post,然后就可以看到生成的token

由于本次项目接口要与微信小程序对接,所以需要安装easyWeChat第三方包,终端进入项目目录:

composer require "overtrue/laravel-wechat:~4.0"  #安装包文件
php artisan vendor:publish --provider="Overtrue\LaravelWeChat\ServiceProvider"   #生成配置文件

打开配置文件wechat.php里面的小程序配置和支付配置,在.env文件中配置支付的相关参数即可。 数据库users表增加字段openidUser模型中增加白名单

接下来,把项目部署上线,配上SSL证书。设置phpstron自动上传,使用https去访问。

(7)、实现接口认证,获取用户信息 在接口控制器MiniController中写上如下代码:

public function auth(Request $request)
{
//        return $request->code;
        $app = EasyWeChat::miniProgram();
        $session = $app->auth->session($request->code);
        $openid = $session['openid'];
         return $openid;

        //用openid查询数据库,是否已经有了,没有就创建。记得改模型白名单
        $user = User::firstOrCreate(compact('openid'));

        //生成token
//        $user = User::first();
        $token = JWTAuth::fromUser($user);
        return response()->json(compact('token'));
  }

测试是否拿到用户的openid

如果报openid错误,就重新刷新小程序,拿code,再去接口调试 如果报表里面的字段没有默认值,就修改users表结构,字段全部允许为NULL 流程总结: 当用户关注微信小程序时,小程序会自动生成一个code,通过接口地址 https://canteen.holyzq.com/api/auth 发给后端,后端接收到code之后,根据这个code去获取用户的openid,然后用openid查询数据库,是否已经有了,没有就创建。最后前端还是通过这个接口地址,获取到后端返回的token,请求所有的接口都要带上。

接下来,测试微信小程序接口数据,新建项目,以开通支付的微信号引入微信小程序前端页面,调用api认证接口地址,查看是否已经获取到后端返回的token

前端调用首页接口地址拿数据,如图:

三、微信支付

1、首先要具备已开通微信支付的微信号,在.env文件中配置好。 2、然后在api.php中的认证接口路由写上如下路由:

Route::prefix('order')->group(function () {
            //生成订单,支付
//            Route::post('/', 'OrderController@store');
            Route::get('pay', 'OrderController@pay');
 });
//支付成功回调,不能过jwt中间件
Route::post('order/notify', 'OrderController@notify');

2、创建对应控制器和方法,写上如下代码:

/***
 * 支付
 */
public function pay()
{
    $payment = EasyWeChat::payment(); // 微信支付

    //计算订单金额
    $count = Cart::count_cart();
    $total_price = $count['total_price'];

    //计算总价格, 以分为单位, 所以: *100
    $total_fee = $total_price * 100;

    /**
     * 第 2 步:统一下单
     */
    $result = $payment->order->unify([
        'body' => '长乐小卖部',
        'out_trade_no' => date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT) . rand(1000, 9999),
        'total_fee' => $total_fee,
        'notify_url' => 'https://***.***.***/api/order/notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
        'trade_type' => 'JSAPI',
        'openid' => JWTAuth::parseToken()->authenticate()->openid,
    ]);

    /**
     * 第 3 步:JSSDK
     */
    if ($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') {
        $prepayId = $result['prepay_id'];
        $jssdk = $payment->jssdk;
        $config = $jssdk->sdkConfig($prepayId);
        return $config;
    } else {
        return $result;
    }

}

/**
 * 微信支付回调方法,修改订单状态
 * @return mixed
 */
function notify()
{
    $payment = EasyWeChat::payment();
    $response = $payment->handlePaidNotify(function ($message, $fail) {

        $order = Order::where('out_trade_no', $message['out_trade_no'])->first();

        // 如果订单存在,表示已经支付了,依然直接true
        if ($order) {
            return true;
        }

        if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态

            // 用户是否支付成功,成功就生成订单
            if (array_get($message, 'result_code') === 'SUCCESS') {
                $this->store($message['openid'], $message['out_trade_no']);
            }
        } else {
            return $fail('通信失败,请稍后再通知我');
        }

        return true; // 返回处理完成
    });

    return $response;
}

3、支付接口测试:

前端调用支付接口,代码如下:

//支付
  pay() {
    if(this.data.count.num == 0) {
      this.show_hint({ show: true, success: false, message: "东西都不选,你买个啥啊?" })
      return;
    }

    wx.request({
      url: 'https://***.***.***/api/order/pay',
      header: {
        'Authorization': this.data.token
      },
      success: (res) => {
        let that = this;
        wx.requestPayment(
          {
            'timeStamp': res.data.timestamp,
            'nonceStr': res.data.nonceStr,
            'package': res.data.package,
            'signType': res.data.signType,
            'paySign': res.data.paySign,

            //成功回调
            'success': function (res) {
              that.setData({
                show_cart: false,
                carts: [],
                cart_nums: {},
                count: { num: 0, total_price: 0}
              })
              that.show_hint({ show: true, success: true, message: "支付成功!" })
            },

            //失败回调
            'fail': function (res) {

              //是否用户主动取消?
              if (res.errMsg == "requestPayment:fail cancel") {
                that.show_hint({ show: true, success: false, message: "你咋取消了支付呢?赶紧买啊!" });
                return;
              }

              //系统故障
              that.show_hint({ show: true, success: false, message: "Shit,谁开发的渣渣,挂球了!叫人吧!" })
            },
            'complete': function (res) { }
          })
      }
    });
  }

最终在微信开发者工具测试结果如下:

Well Done!!!

转载请注明,来自https://itfun.tv/news/152