fly coding 支付插件,Android 对接微信V3App支付功能

63 阅读3分钟

此前,已设计过多应用多平台支付模块的基础开篇。传送门

本篇,准备对接微信V3AppApi支付基础模块,并基于此模块实现具体的业务功能逻辑。

实现思路

一、前期准备工作

1、申请证书

  1. 后台管理选择“API安全“”,进入“API证书管理”进行“申请证书”操作
  2. 下载并打开证书生成工具,按照步骤一步步操作

kf.qq.com/faq/161222N…

  1. 最终会在本地文件夹中生成下图文件

  1. 生成密钥证书

参考文档:github.com/wechatpay-a…

java -jar CertificateDownloader-1.2.0-jar-with-dependencies.jar -f 商户私钥文件路径 
-k 证书解密的密钥 -m 商户号 -o 证书保存路径 -s 商户证书序列号
  • “商户私钥文件路径”通过“账号中心->API安全->API证书”中设置并下载的证书(就是其中的apiclient_key.pem)
  • “商户证书序列号”在“账号中心->API安全->API证书”中;
  • “证书解密的密钥”在“账号中心->API安全->APIv3密钥”中。

二、后端功能开发

1、定义yml配置文件

  • 需求分析,思路梳理

通过阅读微信V3App 文档,梳理以下参数需要动态配置。商户Id、商户密钥、商户证书序列号、商户私钥key、安卓app id。其中,由于商户私钥内容比较大,我准备采用文件路径配置方式存储,其他的则采用yml形式配置。

  • 配置示例如下

1、yml配置示例

2、密钥文件配置示例

2、实现下单扩展

  • 引用V3支付jar
<!-- 微信支付sdk -->
<dependency>
  <groupId>com.github.wechatpay-apiv3</groupId>
  <artifactId>wechatpay-java</artifactId>
  <version>0.2.10</version>
</dependency>
  • 代码实现如下
package com.flycoding.biz.order.factory.impl.wx.v3;

import com.alibaba.fastjson.JSONObject;
import com.flycoding.biz.order.config.OrderDictConfig;
import com.flycoding.biz.order.config.extend.PaymentExtend;
import com.flycoding.biz.order.entity.OrderInfo;
import com.flycoding.biz.order.enums.PayWay;
import com.flycoding.biz.order.factory.impl.base.BasePaymentFactory;
import com.flycoding.biz.order.utils.PayUtils;
import com.flycoding.drivenlibrary.engine.config.constants.DrivenConstants;
import com.flycoding.drivenlibrary.factory.OpenPlatformConfig;
import com.flycoding.utillibrary.java.IDGenerate;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.cipher.SignatureResult;
import com.wechat.pay.java.service.payments.app.AppService;
import com.wechat.pay.java.service.payments.app.model.Amount;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayResponse;

import java.math.BigDecimal;

/**
 * 微信app支付 v3
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2023/3/23 19:41
 * @Copyright(C): 2023 by 赵屈犇
 */
@PaymentExtend(OrderDictConfig.PayWay.WX_APP_API_V3)
public class WxAppV3PaymentFactory extends BasePaymentFactory<JSONObject> {

    @Override
    protected JSONObject placeOrder(OrderInfo orderInfo, OpenPlatformConfig platform) throws Exception {
        // 商户 id
        String mchId = platform.getConfig(DrivenConstants.PlatformConstants.WxConstants.MCH_ID);
        // 安卓app id
        String appId = platform.getConfig(DrivenConstants.PlatformConstants.WxConstants.ANDROID_APP_ID);
        // 获取支付配置
        RSAAutoCertificateConfig config = PayUtils.getWxAppV3Config(platform);
        // 构建service
        AppService service = new AppService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数,具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(orderInfo.getPayMoney().multiply(new BigDecimal(100)).intValue());
        request.setAmount(amount);
        request.setAppid(appId);
        request.setMchid(mchId);
        request.setDescription(orderInfo.getOrderName());
        request.setAttach(orderInfo.getOrderNum());
        request.setNotifyUrl(PayUtils.getNotifyUrl(PayWay.WX_APP_API_V3) + "/" + orderInfo.getOrderNum());
        request.setOutTradeNo(orderInfo.getOrderNum());
        // 调用下单方法,得到应答
        PrepayResponse response = service.prepay(request);
        String prepayId = response.getPrepayId();
        //时间戳
        Long timestamp = System.currentTimeMillis()/ 1000;
        //随机串
        String nonceStr = IDGenerate.getUUId();
        // 签名
        SignatureResult sign = config.createSigner().sign(buildMessage(appId, timestamp, nonceStr, prepayId));
        JSONObject payResult = new JSONObject();
        payResult.put("appId", appId);
        payResult.put("partnerId", mchId);
        payResult.put("sign", sign.getSign());
        payResult.put("prepayId", prepayId);
        payResult.put("nonceStr", nonceStr);
        payResult.put("timestamp", timestamp);
        payResult.put("package", "Sign=WXPay");
        return payResult;
    }

    private String buildMessage(String appId, long timestamp, String nonceStr, String prepayId) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepayId + "\n";
    }
}

三、支付回调

  • 实现回调代码
package com.flycoding.biz.order.api.notify.wx.v3;

import com.flycoding.biz.order.api.notify.base.BasePayNotifyExtend;
import com.flycoding.biz.order.config.OrderResponseConfig;
import com.flycoding.biz.order.entity.OrderInfo;
import com.flycoding.biz.order.entity.wx.v3.WxV3AppNotifyBO;
import com.flycoding.biz.order.utils.PayUtils;
import com.flycoding.drivenlibrary.context.RequestContextHolder;
import com.flycoding.drivenlibrary.engine.annotation.api.Api;
import com.flycoding.drivenlibrary.enums.dictionary.ContentType;
import com.flycoding.drivenlibrary.factory.OpenPlatformConfig;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;

import java.math.BigDecimal;

/**
 * 微信APP V3 支付回调通知
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2023/7/23 16:50
 * @Copyright(C): 2023 by 赵屈犇
 */
@Api(apiUrl = "notify/{orderNum}", apiName = "微信APP V3 支付回调", moduleUrl = "pay/wxAppApi/v3", isVerifyToken = false, isVerifyLogin = false,
        isEncryptedResult = false, isDecryptParams = false, isStartAuth = false, isParseRequestBody = false,
        responseCode = OrderResponseConfig.WX_V3_NOTIFY_RESPONSE, requestContentType = ContentType.NOT_VERIFY
)
public class WxAppV3NotifyExtend extends BasePayNotifyExtend<WxV3AppNotifyBO> {

    @Override
    protected boolean isPaySuccess(OrderInfo orderInfo, OpenPlatformConfig platform) throws Exception {
        // 获取支付配置
        RSAAutoCertificateConfig config = PayUtils.getWxAppV3Config(platform);
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(getRequestHeader("Wechatpay-Serial"))
                .nonce(getRequestHeader("Wechatpay-Nonce"))
                .signature(getRequestHeader("Wechatpay-Signature"))
                .timestamp(getRequestHeader("Wechatpay-Timestamp"))
                .body(RequestContextHolder.getAttributes().getRequestBody())
                .build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        // 以支付通知回调为例,验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if (Transaction.TradeStateEnum.SUCCESS == transaction.getTradeState()) {
            BigDecimal payMoney = BigDecimal.valueOf(transaction.getAmount().getTotal() / 100d);
            getRequestParams().setPayMoney(payMoney);
            return true;
        }
        return false;
    }

}

三、Android功能开发

1、引入jar

// 微信SDK相关
api 'com.tencent.mm.opensdk:wechat-sdk-android:+'

2、实现调用函数

/**
 * 调用微信支付
 *
 * @param context
 * @param wxPayResult
 * @param extData
 */
public void payWxpay(Context context, JSONObject wxPayResult, String extData) {
    PayReq payReq = new PayReq();
    payReq.appId = wxPayResult.getString("appId");
    payReq.partnerId = wxPayResult.getString("partnerId");
    payReq.prepayId = wxPayResult.getString("prepayId");
    payReq.nonceStr = wxPayResult.getString("nonceStr");
    payReq.timeStamp = wxPayResult.getString("timestamp");
    payReq.packageValue = wxPayResult.getString("package");
    payReq.sign = wxPayResult.getString("sign");
    payReq.extData = extData;
    getWXApi(context).sendReq(payReq);
}