微信支付:wxpay.unifiedOrder(data)返回appid 与 openId 不配

原因:小程序和APP、公众号等支付方式夸端口调用支付,后台配置多个appId时

A程序中的openid 在B程序中支付。即使用A程序的openid和B程序的appIdy去调用wxpay.unifiedOrder(data)

把请求统一支付的参数输出:得到当前的appid,微信返回后看到另一个Appid,如果两个一致,则不会出现不匹配问题。不一致,就会报appid 与 openId 不配的错误。

解决方式:由于系统中的WeiXinConfigUtil文件实现了微信SDK的WXPayConfig,多个appid在上送请求支付时对获取APPid做了区分获取,但是没有重写getAppID()方法,导致默认使用appID作为属性的参数值是固定的,在SDK内部获取appid时,不是动态获取,而是配置好的固定值,所以重写getAppID()方法,通过tradeType来区分获取的是哪一个appid

复制代码
package com.wlnl.lanaer.service.api.util;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.github.wxpay.sdk.WXPayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * <p>
 * 微信支付工具类
 * </p>
 *
 * @author luolei
 * @Version: V1.0
 * @since 2019-06-04 21:02
 */
@Slf4j
public class WeiXinConfigUtil implements WXPayConfig {

    private byte[] certData;
    /**
     * 微信支付应用ID app_id
     */
    public static final String APP_ID = "123456789";
    /**
     * 微信支付key
     */
    public static final String KEY = "666666666666";
    /**
     * 微信支付商户号 mch_id
     */
    public static final String MCH_ID = "8888888888";

    public WeiXinConfigUtil() {
        this.certData = getCertStream("apiclient_cert.p12");
    }

    /**
     * 读取resource目录的配置文件
     *
     * @param path : 文件名称
     * @return 返回读取byte数组
     */
    public byte[] getCertStream(String path) {

        try {
            if (StrUtil.isEmpty(path)) {
                throw new Exception("读取文件路径为空");
            }
            ClassPathResource classPathResource = new ClassPathResource(path);
            //获取文件流
            InputStream stream = classPathResource.getInputStream();

            byte[] content = IoUtil.readBytes(stream);
            stream.read(content);
            stream.close();
            return content;
        } catch (IOException e) {
            log.error("读取文件流异常: {}", e.getMessage());
            e.printStackTrace();

        } catch (Exception e) {
            log.error("读取文件路径异常: {}", e.getMessage());
            e.printStackTrace();

        }
        return null;
    }

    @Override
    public String getAppID() {
        return APP_ID;
    }

    //parnerid,商户号
    @Override
    public String getMchID() {
        return MCH_ID;
    }

    @Override
    public String getKey() {
        return KEY;
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return 10000;
    }

}

如果微信支付key和微信支付商户号 mch_id不需要修该时(即多个程序使用的微信支付key和微信支付商户号 mch_id都是同一个)

我们只需要修改微信程序的app_id,这是就可以再创建一个类WeiXinMiniProConfigUtil继承我们上面写的WeiXinConfigUti类,并且重写getAppID()方法,代码如下

复制代码
package com.wlnl.lanaer.service.api.util;
/**
 * @author luolei
 * @version v1.0.1
 * @since 2021/9/7
 **/public class WeiXinMiniProConfigUtil extends WeiXinConfigUtil {

    /**
     * 小程序appid
     * 如果有多个appId的情况不能写死
     */
//    public static final String WX_MINI_PRO_APP_ID = "123456789"; //老版小程序appId
    public static String WX_MINI_PRO_APP_ID = "987654321";

    /**
     * 注意这里一定要重写getAppID()方法,返回我们指定的appId
     * @return
     */
    @Override
    public String getAppID() {
        return WX_MINI_PRO_APP_ID;
    }

    public WeiXinMiniProConfigUtil(){}

    /**
     * 使用可修改的appId,防止appId与openId不匹配的问题
     * @param appId
     */
    public WeiXinMiniProConfigUtil(String appId) {
        WX_MINI_PRO_APP_ID = appId;
    }

}

下面就是测试微信支付是否能下单成功了,代码如下

复制代码
package com.wlnl.lanaer.service.api.mq;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.common.collect.Maps;
import com.wlnl.lanaer.service.api.KxkdApiServiceApplication;
import com.wlnl.lanaer.service.api.constant.enums.ResultEnum;
import com.wlnl.lanaer.service.api.exeception.LanaerException;
import com.wlnl.lanaer.service.api.exeception.OrderExistException;
import com.wlnl.lanaer.service.api.util.WeiXinMiniProConfigUtil;
import com.wlnl.lanaer.service.api.vendors.tencent.pay.WeiXinPayConstant;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * @Description TODO
 * @Date 2023/04/08 15:27
 * @Created by luolie
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {KxkdApiServiceApplication.class})
@AutoConfigureMockMvc
@ExtendWith(SpringExtension.class)
@ActiveProfiles(profiles = "dev")
public class TestWxPush {
    /**
     * 微信下单测试
     */
    @Test
    public void doUnifiedOrderTest() {
        Map map = doUnifiedOrder("5555555555", "111111111111111111");
    }

    /**
     * 小程序支付场景
     */
    public Map doUnifiedOrder(String appId, String openId) {
        try {
            WeiXinMiniProConfigUtil config = new WeiXinMiniProConfigUtil(appId); //使用前端传过来的appId,防止appId与openId不匹配的问题
            WXPay wxpay = new WXPay(config);
            Map<String, String> data = Maps.newHashMap();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("body", "测试微信支付");
            data.put("out_trade_no", "2021WERUN1647840687637");
            data.put("total_fee", "1000"); // 支付金额
            data.put("spbill_create_ip", "59.37.125.120"); //自己的服务器IP地址
            data.put("notify_url", "支付成功后的回调url(外网可访问的https协议的url)");  // 异步通知地址(请注意必须是外网)
            data.put("trade_type", "JSAPI");
            data.put("openid", openId); // trade_type是JSAPI的时候,必须有openid
            data.put("sign", WXPayUtil.generateSignature(data, config.getKey()));
            //使用官方API请求预付订单
            Map<String, String> response = wxpay.unifiedOrder(data);
            //主要返回以下5个参数
            if (WeiXinPayConstant.WEIXIN_PAY_RESULT_SUCCESS.equals(response.get(WeiXinPayConstant.WEIXIN_PARY_RETURN_CODE)) && WeiXinPayConstant.WEIXIN_PAY_RESULT_SUCCESS.equals(response.get(WeiXinPayConstant.WEIXIN_RESULT_CODE))) {
                Map<String, String> param = Maps.newHashMap();
                param.put("appId", config.getAppID());
                param.put("timeStamp", System.currentTimeMillis() / 1000 + "");
                param.put("nonceStr", WXPayUtil.generateNonceStr());
                param.put("package", "prepay_id=" + response.get("prepay_id"));
                param.put("signType", "MD5");
                param.put("sign", WXPayUtil.generateSignature(param, config.getKey()));
                // 以下是返回的
                param.put("partnerid", response.get("mch_id"));
                param.put("prepayid", response.get("prepay_id"));
                param.put("body", "测试微信支付");
                param.put("out_trade_no", "2021WERUN1647840687637");
                param.put("total_fee", "1000");
                return param;
            } else {
                String err_code = response.get("err_code");
                // 商户订单号重复
                if (!StringUtils.isEmpty(err_code) && "INVALID_REQUEST".equals(err_code)) {
                    throw new OrderExistException(response.get(WeiXinPayConstant.WEIXIN_ERR_CODE_DESG));
                }
                // 订单创建失败
                if (WeiXinPayConstant.WEIXIN_PAY_RESULT_FALL.equals(response.get(WeiXinPayConstant.WEIXIN_PARY_RETURN_CODE))) {
                    throw new LanaerException(response.get(WeiXinPayConstant.WEIXIN_PARY_RETURN_MSG));
                }
                String err_code_des = response.get("err_code_des");
                if (StringUtils.hasLength(err_code_des)) {
                    throw new LanaerException(err_code_des);
                }
            }
        } catch (OrderExistException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new LanaerException(ResultEnum.ERROR_CODE.getCode(), "下单失败");
        }
        throw new LanaerException(ResultEnum.ERROR_CODE.getCode(), "下单失败");
    }
}
相关推荐
考虑考虑10 小时前
Jpa使用union all
java·spring boot·后端
用户37215742613511 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊12 小时前
Java学习第22天 - 云原生与容器化
java
渣哥14 小时前
原来 Java 里线程安全集合有这么多种
java
间彧14 小时前
Spring Boot集成Spring Security完整指南
java
间彧14 小时前
Spring Secutiy基本原理及工作流程
java
Java水解15 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆17 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学18 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole18 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端