前段时间一个朋友使用laravel5.5框架做微信公众号的开发,项目引用了overtrue的laravel-wechat3.0插件,然后让我帮他接入微信支付。在浏览众多相关的文档及尝试了各路开发者的案例后,功夫不负有心人,成功完成了任务,下面是我简单而又详细的介绍接入微信公众号支付的流程(附完整源码):
接入微信支付的准备工作我就不一一说明了,无非是申请微信的服务号并认证,申请开通微信支付,然后分别登录微信公众平台和商户平台进行相关信息的获取与配置了。建议先行阅读官方的微信公众号支付文档。
1、发起生成订单的ajax请求(可忽略)
function generate_order() { $.ajax({ type: 'POST', url: '/order/generateorder', data: { id : '{ {$goods->id}}', buy_count : $('.shu').text(),_token:'{ {csrf_token()}}'}, dataType: 'json', success: function(data){ // console.log(data.msg); let url_pre = '{ {url("wxpay/orderpay")}}'; window.location.href = url_pre + "/" + data.order_id; }, error: function(xhr, type){ alert('Ajax error!'); } }); }
上面的function的作用:生成一个订单,成功即跳到后台payOrder函数,路由设置:
Route::get('wxpay/orderpay/{id}','mobile\WxPayController@payOrder');
2、下面是mobile\WxPayController控制器代码:
'xxx', //你的APPID 'secret' => 'xxx', // AppSecret 'token' => 'xxx', // Token 'aes_key' => 'xxx', // EncodingAESKey,安全模式下请一定要填写!!! // ... // payment 'payment' => [ 'merchant_id' => 'xxx', // 微信支付商户号 'key' => 'xxx',// API秘钥 'cert_path' => '/usr/local/nginx/cert/apiclient_cert.pem', // XXX: 绝对路径!!!! 'key_path' => '/usr/local/nginx/cert/apiclient_key.pem', // XXX: 绝对路径!!!! 'notify_url' => url("wxpay/notify"), //你的回调地址 你也可以在下单时单独设置来想覆盖它 // 'device_info' => '013467007045764', // 'sub_app_id' => '', // 'sub_merchant_id' => '', // ... ], ]; } public function payOrder($order_id) { //支付订单页面 //$order_id = Input::get('id'); $order_find = \App\Http\Models\Order::find($order_id); if(empty($order_find)) return Redirect::back()->withInput()->withErrors('该订单无效!'); //$js = EasyWeChat::js(); $options = $this->options(); $app = new Application($options); $payment = $app->payment; $out_trade_no = md5(uniqid().microtime()); //拼一下商户订单号 $user = (session('wechat.oauth_user'))->toArray(); $attributes = [ 'trade_type' => 'JSAPI', // JSAPI,NATIVE,APP... 'body' => '商品支付', 'detail' => '商品详情', //商品详情,你也可以自定义 'out_trade_no' => $out_trade_no, //商户订单号 'total_fee' => $order_find->order_amount*100, //因为是以分为单位,所以订单里面的金额乘以100 // 'notify_url' => 'http://xxx.com/order-notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址 'openid' => $user['original']['openid'], // trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识,当前用户的 openid // ... ]; $order = new Order($attributes); $result = $payment->prepare($order); if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { $res1 = DB::table('order') ->where('id', $order_id) ->update(['out_trade_no' => $out_trade_no]);//在这里更新订单的支付ID // return response()->json(['result'=>$result]); $prepayId = $result->prepay_id; $config = $payment->configForJSSDKPayment($prepayId); $js = $app->js; // 这个是jssdk里页面上需要用到的js参数信息。 return view('mobile.wxpay.payOrder') ->withConfig($config) ->withJs($js) ->withOrder($order_find); } } //下面是回调函数 public function notify(Request $request) {// Log::info('come in notify()'); $options = $this->options(); $app = new Application($options); $response =$app->payment->handleNotify(function($notify, $successful){ // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单 $order = \App\Http\Models\Order::where('out_trade_no',$notify->out_trade_no)->first(); if (count($order) == 0) { // 如果订单不存在 return 'Order not exist.'; // 告诉微信,我已经处理完了,订单没找到,别再通知我了 } // 如果订单存在 // 检查订单是否已经更新过支付状态 if ($order->pay_time) { // 假设订单字段“支付时间”不为空代表已经支付 return true; // 已经支付成功了就不再更新了 } // 用户是否支付成功 if ($successful) {// Log::info('支付成功'); // 不是已经支付状态则修改为已经支付状态 $res1 = DB::table('order') ->where('out_trade_no', $notify->out_trade_no) ->update(['pay_time' => time(),'order_status' => 2]);//已支付 } else { // 用户支付失败// Log::info('支付失败'); $res2 = DB::table('order') ->where('out_trade_no', $notify->out_trade_no) ->update(['order_status' => 1]);//待付款 } return true; // 返回处理完成 });// Log::info($response); return $response; }}
3、mobile.wxpay.payOrder文件--HTML5页面:
@extends('mobile.mobile')@section('title', '支付订单')@section('header')@endsection@section('main') @endsection@section('javaScript') @endsection
点击‘确认支付’,即调用微信jsapi发起支付。
4、微信支付回调网址路由设置:(注意不要把它放到任何验证类型的中间件里)
Route::any('wxpay/notify','mobile\WxPayController@notify');
支付结果通知回调,是支付完成后微信服务器通过post方式回调返回支付结果信息,所以回调接口地址一定是在公网直接可以访问的,Laravel 5 默认启用了 CSRF 中间件,因为微信的消息是 POST 过来,所以会触发 CSRF 检查导致无法正确响应消息,所以可以在CSRF验证中排除指定URL。可以通过在VerifyCsrfToken
(app/Http/Middleware/VerifyCsrfToken.php
)中间件中将要排除的请求URL添加到$except
属性数组中,如下:
5、至此,基本done了,代码不够优雅或者有任何改进的地方,请指教。。