微信小程序支付(服务商模式)解决

前言

微信支付官方文档: 小程序开发与支付、服务商的关系,参考这个文档

1、第三方(服务商)自己申请账号,自己开发,生成指定内页给特约商户用,该模式简称中心化模式。

2、以特约商户身份申请小程序appId,第三方完成开发,该模式简称外包模式。 3、通过开放平台第三方开发者代特约商户进行小程序的开发,该模式简称第三方模式。

本文适用于中心化模式,服务商自己开发一个小程序,但是收款是直接受到对应的特约商户账户中,不收到服务商自己账户中。

基本流程

服务商再微信后台申请微信小程序
小程序开通微信支付或绑定已开通微信支付的商户号

特约商户需要操作的流程

服务商再微信支付商户后台,为特约商户开通微信服务商模式下的微信支付账户
特约商户在收到微信邮件发送的登录账号和密码,登录自己的微信支付商户后台,绑定小程序的appId
提交审核,被拒绝的话再次提交审核,直到审核通过
服务商管理后台中找到”待关联商户号”并确认
登录微信支付服务商商户后台,手动为特约商户绑定与服务商主体或特约商户主体一致的公众号,APP或小程序的appId。最多配置5个,手工配置路径:”服务商商户平台-服务商功能-子商户管理-开发配置-特约商户APPID配置”。

支付部分

appid:注意这里是服务号的appid,不是小程序的
mch_id:这里是用服务商的id 在我的账号一栏可以找到
sub_appid: 这里才是小程序的appid
sub_mch_id: 这里对应特约商户号id 付款到对应商户的凭证就是这个 在注册特约商户的时候邮件里可以找到 这里建议配置到数据库动态传递
nonce_str: 随机字符串
body: 这里随意填写,也可以填写商品名称
out_trade_no: 订单号
total_fee: 这里必须是整数,单位是分
trade_type: 公众平台支付或小程序支付填写:JSAPI,如果是APP的填写:APP
sub_openid: 此参数是在发起支付前在小程序内调起wx.login 方法获得code 然后后台通过置换 获得用户openid
spbill_create_ip:这里可以随意填写
notify_url: 支付回调的地址
sign: 此参数为签名参数 需要将需要传递的参数进行排序并且进行md5签名,需要注意的是需添加参数key 即之前修改的服务商api密钥

好了 参数分析完毕 在后台调用统一下单方法 不出意外是成功的,下单代码如下:

Controller部分

@RestController
@RequestMapping"/payment")
public class WxPayController {

    private Logger logger = LoggerFactory.getLoggerWxLoginController.class);

    @Autowired
    private AppletOrderService appletOrderService;

    @Autowired
    private WxPayProperties wxPayProperties;

    @ResponseBody
    @PostMappingvalue = "/appletWxPay", produces = "application/json;charset=UTF-8")
    public Map<Object, Object> appletWxPay@RequestParam String openId, String totalFee) throws Exception {
        logger.info"[WxPayController].appletWxPay...openId:{}", openId);
        SortedMap<Object, Object> resultMap = new TreeMap<Object, Object>);
        String body = "测试";
        String out_trade_no = String.valueOfIdWorker.getInstance).nextId));
        PreOrderResult preOrderResult = appletOrderService.placeOrderbody, out_trade_no, totalFee, openId);
        System.out.printlnpreOrderResult);

        ifWxContants.SUCCESS.equalspreOrderResult.getReturn_code)) && WxContants.SUCCESS.equalspreOrderResult.getResult_code))){
            resultMap.put"appId", wxPayProperties.getApp_id));
            resultMap.put"timeStamp", Long.toStringSystem.currentTimeMillis)/1000));
            resultMap.put"nonceStr", UUID.randomUUID).toString).replaceAll"-", "").toUpperCase));
            resultMap.put"package", "prepay_id="+preOrderResult.getPrepay_id));
            resultMap.put"signType", "MD5");
            resultMap.put"sign", SignUtils.createSignByMd5resultMap, wxPayProperties.getKey)));
            resultMap.put"returnCode", "SUCCESS");
            resultMap.put"returnMsg", "OK");
            logger.info"【小程序支付】统一下单成功,返回参数:"+resultMap);
        }else{
            resultMap.put"returnCode", preOrderResult.getReturn_code));
            resultMap.put"returnMsg", preOrderResult.getReturn_msg));
            logger.info"【小程序支付】统一下单失败,失败原因:{}" + preOrderResult.getReturn_msg));
        }
        logger.info"[WxPayController].appletWxPay...CodeUrl:{}", preOrderResult.getCode_url));
        return resultMap;
    }

}

Serivice部分

@Service
public class AppletOrderServiceImpl implements AppletOrderService{

    @Autowired
    private WxPayProperties wxPayProperties;

    @Override
    public PreOrderResult placeOrderString body, String out_trade_no, String total_fee, String openId) throws Exception {
        // 生成预付单对象
        PreOrder preOrder = new PreOrder);
        preOrder.setAppidwxPayProperties.getApp_id));
        preOrder.setMch_idwxPayProperties.getMch_id));
        preOrder.setSub_appidwxPayProperties.getSub_app_id));
        preOrder.setSub_mch_idwxPayProperties.getSub_mch_id));
        String nonce_str = UUID.randomUUID).toString).replaceAll"-", "").toUpperCase);
        preOrder.setNonce_strnonce_str);

        preOrder.setBodybody);
        preOrder.setOut_trade_noout_trade_no);

        preOrder.setTotal_feenew BigDecimaltotal_fee));
        preOrder.setSpbill_create_ipwxPayProperties.getSpbill_create_ip));
        preOrder.setNotify_urlwxPayProperties.getNotify_url));
        preOrder.setTrade_typeWxContants.TRADE_TYPE);
        preOrder.setSub_openidopenId);
        SortedMap<Object, Object> p = new TreeMap<Object, Object>);
        p.put"appid", wxPayProperties.getApp_id));
        p.put"mch_id", wxPayProperties.getMch_id));
        p.put"sub_appid", wxPayProperties.getSub_app_id));
        p.put"sub_mch_id", wxPayProperties.getSub_mch_id));
        p.put"body", body);
        p.put"nonce_str", nonce_str);
        p.put"out_trade_no", out_trade_no);
        p.put"total_fee", total_fee);
        p.put"spbill_create_ip", wxPayProperties.getSpbill_create_ip));
        p.put"notify_url", wxPayProperties.getNotify_url));
        p.put"trade_type", WxContants.TRADE_TYPE);
        p.put"sub_openid", openId);
        // 签名
        String sign = SignUtils.createSignByMd5p, wxPayProperties.getKey));
        preOrder.setSignsign);
        String xml = XmlUtil.object2XmlpreOrder, PreOrder.class);
        // 调用下单地址
        String returnXml = HttpUtil.sendPostWxContants.pay_url, xml);
        System.out.printlnreturnXml);
        // XML转换为Object
        PreOrderResult preOrderResult = PreOrderResult) XmlUtil.xml2ObjectreturnXml, PreOrderResult.class);
        // XML转换为Object
        // 一般企业开发中支付流水入库,支付状态更新这些都需要做,此出省略
        return preOrderResult;
    }

    @Override
    public PayResult getWxPayResultHttpServletRequest request) throws Exception {
        InputStream inStream = request.getInputStream);
        BufferedReader in = null;
        String result = "";
        in = new BufferedReader
                new InputStreamReaderinStream));
        String line;
        while line = in.readLine)) != null) {
            result += line;
        }
        PayResult pr = PayResult)XmlUtil.xml2Objectresult, PayResult.class);
        System.out.printlnpr.toString));
        return pr;
    }

}

小程序配置部分

@Component
public class WxPayProperties {

    @Value"${wxpay.app_id}")
    private String app_id;

    @Value"${wxpay.sub_app_id}")
    private String sub_app_id;

    @Value"${wxpay.spbill_create_ip}")
    private String spbill_create_ip;

    @Value"${wxpay.key}")
    private String key;

    @Value"${wxpay.mch_id}")
    private String mch_id;

    @Value"${wxpay.sub_mch_id}")
    private String sub_mch_id;

    @Value"${wxpay.notify_url}")
    private String notify_url;

    // 此处省略get/set方法
    ...
        
}

返回数据

{
    "appId": "wxe670bb9ea4775345",
    "nonceStr": "536D9056202D4292A909392320E2E5BB",
    "package": "prepay_id=wx13143641616855cfa3275610dd2a070000",
    "returnCode": "SUCCESS",
    "returnMsg": "OK",
    "sign": "C512D4025134C356BFA58A2F5699E198",
    "signType": "MD5",
    "timeStamp": "1610519802"
}

小程序端根据后台返回的参数,拉起支付,代码如下:

wx.requestPayment{
	'timeStamp': res.data.timeStamp,
	'nonceStr': res.data.nonceStr,
	'package': res.data.package,
	'signType': res.data.signType,
	'paySign': res.data.sign,
	'success':functionres){},
	'fail':functionres){},
	'complete':functionres){}
})

点击支付,总算是来到了这一步:

image-20210113144740860

过程中,可能会遇到如下问题:

https://note.youdao.com/yws/api/personal/file/75A86A993B104245B319B1F2D7B53BFE?method=download&shareKey=295148895adc01c00c7578849dd50e26

出现这个错误的原因是签名不正确,多检查检查是哪一步出现了问题。

最后

一路踩了不少坑,总算还是成功了,因此将解决方法记录下来,后面做小程序支付功能的小伙伴可以避免踩坑。

__EOF__

作  者:Jerry
出  处:https://www.cnblogs.com/jerry0612/p/14272073.html
关于博主:编程路上的小学生,热爱技术,喜欢专研。评论和私信会在第一时间回复。或者直接私信我。
版权声明:署名 – 非商业性使用 – 禁止演绎,协议普通文本 | 协议法律文本
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐】一下。您的鼓励是博主的最大动力!

 
 

Published by

风君子

独自遨游何稽首 揭天掀地慰生平