uni-app开发经验分享八: 实现微信APP支付的全过程详解

前端之家收集整理的这篇文章主要介绍了uni-app开发经验分享八: 实现微信APP支付的全过程详解,前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

背景

最近项目使用uni-app实现微信支付,把过程简单记录下,帮助那些刚刚基础uni-app,苦于文档的同学们。
整体来说实现过程和非uni-app的实现方式没有太大不同,难点就在于uni-app对于orderInfo的格式没有说明。

准备工作

  1. 申请了商户号,拿到了API秘钥。这个需要微信开发平台,相关的工作大家百度。
  2. 后面代码里用到的appid和秘钥之类需要实现申请号。
  3. 在uni-app manifest.json 配置sdk支付权限

uni-app开发经验分享八: 实现微信APP支付的全过程详解

 

 

 

前端代码

  1. onload阶段获取了可用支付列表,这里我们只用到了微信支付。
  2. requestPayment  

          a. getOrderInfo 获取到订单信息,主要是prepayid,对应统一下单api的返回值。

          b. uni.requestPayment发起支付,效果就是弹出微信支付框输入密码支付。第一个参数是“wxpay”,第二个参数就是OrderInfo.

前端代码很简单,重点是如何让后端返回OrderInfo以及OrderInfo的格式。

  

前端代码如下:

<template>

<view>

<page-head :title="title"></page-head>

<view class="uni-padding-wrap">

<view>

<view class="uni-hello-text uni-center">支付金额</text></view>

<view class="uni-h1 uni-center uni-common-mt">

<text class="rmbLogo">¥</text>

<input class="price" type="digit" :value="price" maxlength="4" @input="priceChange" />

</view>

</view>

<view class="uni-btn-v uni-common-mt">

<!-- #ifdef APP-PLUS -->

<template v-if="providerList.length > 0">

<button v-for="(item,index) in providerList" :key="index" @click="requestPayment(item,index)"

:loading="item.loading">{{item.name}}支付</button>

</template>

<!-- #endif -->

</view>

</view>

</view>

</view>

</template>

<script>

export default {

data() {

return {

title: 'request-payment',loading: false,price: 1,providerList: []

}

},onLoad: function() {

// #ifdef APP-PLUS

uni.getProvider({

service: "payment",success: (e) => {

console.log("payment success:" + JSON.stringify(e));

let providerList = [];

e.provider.map((value) => {

switch (value) {

case 'alipay':

providerList.push({

name: '支付宝',id: value,loading: false

});

break;

case 'wxpay':

providerList.push({

name: '微信',loading: false

});

break;

default:

break;

}

})

this.providerList = providerList;

},fail: (e) => {

console.log("获取支付通道失败:",e);

}

});

// #endif

},methods: {

async requestPayment(e,index) {

this.providerList[index].loading = true;

let orderInfo = await this.getOrderInfo(e.id);

console.log("得到订单信息",orderInfo);

if (orderInfo.statusCode !== 200) {

console.log("获得订单信息失败",orderInfo);

uni.showModal({

content: "获得订单信息失败",showCancel: false

})

return;

}

uni.requestPayment({

provider: e.id,orderInfo: orderInfo.data.data,success: (e) => {

console.log("success",e);

uni.showToast({

title: "感谢您的赞助!"

})

},fail: (e) => {

console.log("fail",e);

uni.showModal({

content: "支付失败,原因为: " + e.errMsg,showCancel: false

})

},complete: () => {

this.providerList[index].loading = false;

}

})

},getOrderInfo(e) {

let appid = "";

// #ifdef APP-PLUS

appid = plus.runtime.appid;

// #endif

let url = 'http://10.10.60.200:8070/sc-admin/sales/wx/prepay/?brokerId=shba01';

return new Promise((res) => {

uni.request({

url: url,success: (result) => {

res(result);

},fail: (e) => {

res(e);

}

})

})

},priceChange(e) {

console.log(e.detail.value)

this.price = e.detail.value;

}

}

}

</script>

<style>

.rmbLogo {

font-size: 40upx;

}

button {

background-color: #007aff;

color: #ffffff;

}

.uni-h1.uni-center {

display: flex;

flex-direction: row;

justify-content: center;

align-items: flex-end;

}

.price {

border-bottom: 1px solid #eee;

width: 200upx;

height: 80upx;

padding-bottom: 4upx;

}

.ipaPayBtn {

margin-top: 30upx;

}

</style>

  

后端代码(springboot)

核心代码

import com.alibaba.fastjson.JSONObject;

import com.bian.common.core.domain.AjaxResult;

import com.bian.common.utils.StringUtils;

import com.bian.framework.config.jwt.AuthService;

import com.bian.sales.entity.Constant;

import com.bian.sales.entity.PayInfo;

import com.bian.sales.service.IWxService;

import com.bian.sales.util.*;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.web.client.RestTemplate;

import com.thoughtworks.xstream.XStream;

import org.springframework.http.HttpEntity;

import org.slf4j.Logger;

import javax.servlet.http.HttpServletRequest;

import java.util.*;

@Service

public class WxServiceImpl implements IWxService

{

Logger logger = LoggerFactory.getLogger(WxServiceImpl.class);

@Override

public AjaxResult goWeChatPay(String brokerId,HttpServletRequest request) throws Exception {

String clientIP = CommonUtil.getClientIp(request);

logger.error("openId: " + brokerId + ",clientIP: " + clientIP);

String randomNonceStr = RandomUtils.generateMixString(32);

Map<String,String> result = unifiedOrder(brokerId,clientIP,randomNonceStr);

System.out.println(request.toString());

if(StringUtils.isBlank(result.get("prepay_id"))) {

return AjaxResult.error("支付错误");

} else {

logger.info("支付成功");

Map <String,Object>jsonObject = new LinkedHashMap();

String noncestr = RandomUtils.generateMixString(32);

String prepayid = result.get("prepay_id");

String timestamp = String.valueOf(new Date().getTime()/1000);

jsonObject.put("appid",Constant.APP_ID);

jsonObject.put("noncestr",noncestr);

jsonObject.put("package","Sign=WXPay");

jsonObject.put("partnerid",Constant.MCH_ID);

jsonObject.put("prepayid",result.get("prepay_id"));

jsonObject.put("timestamp",new Date().getTime()/1000);

jsonObject.put("sign",getSignforPayment(noncestr,prepayid,timestamp ));

return AjaxResult.success(jsonObject);

}

}

/**

* @Function: 去支付

* @author: YangXueFeng

* @Date: 2019/6/14 16:50

*/

/**

* 调用统一下单接口

* @param brokerId

*/

private Map<String,String>

(String brokerId,String clientIP,String randomNonceStr) {

try {

//生成预支付交易单,返回正确的预支付交易会话标识后再在APP里面调起支付

String url = Constant.URL_UNIFIED_ORDER;

PayInfo payInfo = createPayInfo(brokerId,randomNonceStr);

String md5 = getSign(payInfo);

payInfo.setSign(md5);

logger.error("md5 value: " + md5);

String xml = CommonUtil.payInfoToXML(payInfo);

xml = xml.replace("__","_").replace("<![CDATA[1]]>","1");

//xml = xml.replace("__","_").replace("<![CDATA[","").replace("]]>","");

logger.error(xml);

StringBuffer buffer = HttpUtil.httpsRequest(url,"POST",xml);

logger.error("unifiedOrder request return body: \n" + buffer.toString());

Map<String,String> result = CommonUtil.parseXml(buffer.toString());

String return_code = result.get("return_code");

if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) {

String return_msg = result.get("return_msg");

if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {

logger.error("统一下单错误!");

return null;

}

String prepay_Id = result.get("prepay_id");

return result;

} else {

return null;

}

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

/**

* 生成统一下单接口的请求参数

* https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

* @param brokerId

* @param clientIP

* @param randomNonceStr

* @return

*/

private PayInfo createPayInfo(String brokerId,String randomNonceStr) {

clientIP ="222.72.148.34";

Date date = new Date();

String timeStart = TimeUtils.getFormatTime(date,Constant.TIME_FORMAT);

String timeExpire = TimeUtils.getFormatTime(TimeUtils.addDay(date,Constant.TIME_EXPIRE),Constant.TIME_FORMAT);

String randomOrderId = CommonUtil.getRandomOrderId(); //生成随机商品订单号

PayInfo payInfo = new PayInfo();

payInfo.setAppid(Constant.APP_ID);

payInfo.setMch_id(Constant.MCH_ID);

payInfo.setDevice_info("WEB");

payInfo.setNonce_str(randomNonceStr);

payInfo.setSign_type("MD5"); //默认即为MD5

payInfo.setBody("必安glJSAPI支付测试");

payInfo.setAttach("支付测试4luluteam");

payInfo.setOut_trade_no(randomOrderId);

payInfo.setTotal_fee(1);

payInfo.setSpbill_create_ip(clientIP);

payInfo.setTime_start(timeStart);

payInfo.setTime_expire(timeExpire);

payInfo.setNotify_url(Constant.URL_NOTIFY);

payInfo.setTrade_type("APP");

payInfo.setLimit_pay("no_credit");

// payInfo.setOpenid(brokerId);

return payInfo;

}

private String getSign(PayInfo payInfo) throws Exception {

StringBuffer sb = new StringBuffer();

sb.append("appid=" + payInfo.getAppid())

.append("&attach=" + payInfo.getAttach())

.append("&body=" + payInfo.getBody())

.append("&device_info=" + payInfo.getDevice_info())

.append("&limit_pay=" + payInfo.getLimit_pay())

.append("&mch_id=" + payInfo.getMch_id())

.append("&nonce_str=" + payInfo.getNonce_str())

.append("&notify_url=" + payInfo.getNotify_url())

// .append("&openid=" + payInfo.getOpenid())

.append("&out_trade_no=" + payInfo.getOut_trade_no())

.append("&sign_type=" + payInfo.getSign_type())

.append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())

.append("&time_expire=" + payInfo.getTime_expire())

.append("&time_start=" + payInfo.getTime_start())

.append("&total_fee=" + payInfo.getTotal_fee())

.append("&trade_type=" + payInfo.getTrade_type())

.append("&key=" + Constant.API_KEY);

System.out.println("排序后的拼接参数:" + sb.toString());

return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();

}

private String getSignforPayment(String noncestr,String prepayid,String timestamp) throws Exception {

StringBuffer sb = new StringBuffer();

sb.append("appid=" +Constant.APP_ID)

.append("&noncestr=" + noncestr)

.append("&package=" + "Sign=WXPay")

.append("&partnerid=" + Constant.MCH_ID)

.append("&prepayid=" + prepayid)

.append("&timestamp=" + timestamp)

.append("&key=" + Constant.API_KEY);

System.out.println("排序后的拼接参数:" + sb.toString());

return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();

}

}

  

代码说明
以上代码goWeChatPay从controller层跳转并返回结果给controller接口。所有过程参考微信官方文档的2个接口

  1. 统一下单接口后端

  2. 调起支付接口前端已实现

unifiedOrder对应了统一下单接口,看起来很复杂,其实就做了一件事就是拼接参数。拼接参数时涉及到了签名算法,理解这个算法是关键,建议花时间理解透彻这个算法。

createPayInfo,创建一个PayInfo的类,对应了提交的各个参数。
getSign,签名算法的具体实现,获得提交参数的sign。

以上完成了统一下单接口的过程,如果return_code返回“SUCCESS”,result_code返回OK,我们会获得prepay_id(预支付交易会话标识),到这里已经完成了后端内容。但为了使用uni-app我们需要按照如下格式返回给前端,

 

格式如下:

{"data": {

"appid": "wx0411fa6a39d61297","noncestr": "5JigiIJicbq8hQI2","package": "Sign=WXPay","partnerid": "1230636401","prepayid": "wx21204902147233e222e12d451613768000","timestamp": 1571662142,"sign": "0E5C9B9B1C8D7497A234CCC3C721AB1F"

},"statusCode": 200,"header": {

"Content-Type": "text/plain;charset=UTF-8","X-Android-Response-Source": "NETWORK 200","Date": "Mon,21 Oct 2019 12:49:02 GMT","EagleId": "74cf71a315716621419605339e","Vary": "[Accept-Encoding,Accept-Encoding]","X-Android-Received-Millis": "1571662145735","Timing-Allow-Origin": "*","_": "HTTP/1.1 200 OK","X-Android-Selected-Protocol": "http/1.1","Connection": "keep-alive","Via": "cache28.l2et15-1[208,0],kunlun5.cn1241[504,0]","X-Android-Sent-Millis": "1571662145071","Access-Control-Allow-Origin": "*","Server": "Tengine","Transfer-Encoding": "chunked"

},"errMsg": "request:ok"

}

  

重点是data部分,就是uni-app要求的OrderInfo的格式,getSignforPayment就是该部分的签名算法。

以上如果实行正确,应该就可以正常发起微信支付。

参考文档

https://blog.csdn.net/zhuoganliwanjin/article/details/81872215

总结


以上是前端之家为你收集整理的uni-app开发经验分享八: 实现微信APP支付的全过程详解全部内容,希望文章能够帮你解决uni-app开发经验分享八: 实现微信APP支付的全过程详解所遇到的程序开发问题。

如果觉得前端之家网站内容还不错,欢迎将前端之家网站推荐给前端开发程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

以上是 uni-app开发经验分享八: 实现微信APP支付的全过程详解 的全部内容, 来源链接: utcz.com/a/129529.html

回到顶部