uni-app微信、支付宝小程序-银联支付

准备材料

1、跟银联支持人员开通的账号信息

商户号:898330671212
终端号:00000001
消息来源(msgSrc):WWW.ZJABC.COM
来源编号(msgSrcId):12Q5
通讯密钥: 3r4bNXdbdjbJT4x4SDFD89S0DFSDF890SDF8SD90
机构商户号(instMid): MINIDENSDFD
交易地址:https://qr.chinaums.com/netpay-route-server/api/

Java端代码编写

1、配置类编写

    @Getter
    @Setter
    public static class UnionPay {
        //  交易地址
        private String gateway = "https://qr.chinaums.com/netpay-route-server/api/";
        //  商户号
        private String mchId;
        //  终端号
        private String terminalId;
        //  消息来源
        private String msgSrc;
        //  来源编号
        private String msgSrcId;
        //  机构商户号
        private String instMid;
        //  通讯密钥
        private String communicationKey;
        //  支付回调地址
        private String notifyUrl;
    }

2、dev.yml配置

![image.png](https://img-blog.csdnimg.cn/img_convert/071a12935fc78967a53fba47560f8602.png#clientId=u80c99cc0-618d-4&from=paste&height=206&id=u08da5aac&margin=[object Object]&name=image.png&originHeight=206&originWidth=735&originalType=binary&ratio=1&size=130002&status=done&style=none&taskId=u66d99c00-662a-4b8e-bb36-b6a42a52c3c&width=735)

3、Util工具类

这个类目前主要用于签名

package com.nis.smart_charge.utils.unionpay;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class UnionPayUtils {


    /**
     * 构建签名
     *
     * @param md5Key
     * @param params
     * @return
     */
    public static String makeSign(String md5Key, Map<String, Object> params) {
        String preStr = buildSignString(params); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        String text = preStr + md5Key;
        return DigestUtils.sha256Hex(getContentBytes(text)).toUpperCase();
    }

    /**
     * 构建签名字符串
     *
     * @param params
     * @return
     */
    private static String buildSignString(Map<String, Object> params) {

        if (params == null || params.size() == 0) {
            return "";
        }

        List<String> keys = new ArrayList<>(params.size());

        for (String key : params.keySet()) {
            if ("sign".equals(key)) {
                continue;
            }
            if (StringUtils.isEmpty(params.get(key).toString())) {
                continue;
            }
            keys.add(key);
        }

        Collections.sort(keys);

        StringBuilder buf = new StringBuilder();

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key).toString();

            if (i == keys.size() - 1) {
                // 拼接时,不包括最后一个&字符
                buf.append(key).append("=").append(value);
            } else {
                buf.append(key).append("=").append(value).append("&");
            }
        }

        return buf.toString();
    }

    /**
     * 根据编码类型获得签名内容byte[]
     *
     * @param content 签名内容
     * @return 返回签名内容字节数组
     */
    private static byte[] getContentBytes(String content) {
        return content.getBytes(StandardCharsets.UTF_8);
    }

}

4、支付下单

package com.nis.smart_charge.modules.consumer.service.unionpay.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.nis.smart_charge.config.AppProperties;
import com.nis.smart_charge.exception.problem.BadCredentialProblem;
import com.nis.smart_charge.exception.problem.BusinessErrorProblem;
import com.nis.smart_charge.modules.consumer.domain.vo.wechat.MicroPayVo;
import com.nis.smart_charge.modules.consumer.service.unionpay.IUnionPayService;
import com.nis.smart_charge.security.CurrentUser;
import com.nis.smart_charge.utils.security.SecurityUtils;
import com.nis.smart_charge.utils.unionpay.UnionPayUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 银联支付相关接口
 *
 * @author lwj
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionPayServiceImpl implements IUnionPayService {

    private final AppProperties appProperties;

    @Override
    public MicroPayVo microAppPayOrder(Long code, Long merchantId, BigDecimal amount, String description) {
        final CurrentUser currentUser = SecurityUtils.getCurrentLogin().orElseThrow(BadCredentialProblem::new);
        final AppProperties.UnionPay unionPay = appProperties.getUnionPay();
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("mid", unionPay.getMchId());
        paramsMap.put("tid", unionPay.getTerminalId());
        //	区分支付方式(微信wx.unifiedOrder;支付宝trade.create;云闪付uac.miniOrder)
        paramsMap.put("msgType", "wx.unifiedOrder");
        paramsMap.put("msgSrc", unionPay.getMsgSrc());
        paramsMap.put("instMid", unionPay.getInstMid());
        paramsMap.put("merOrderId", unionPay.getMsgSrcId() + code);
        //  获取订单总金额,单位为分,系统默认金额单位为元,需要进行转换,amount必须为string类型,
        Integer amountStr = amount.multiply(new BigDecimal(100)).intValue();
        paramsMap.put("totalAmount", amountStr);
        paramsMap.put("tradeType", "MINI");
        //  微信和支付宝小程序的用户id
        paramsMap.put("subOpenId", currentUser.getWxOpenId());
        paramsMap.put("userId", currentUser.getAlipayOpenId());

        //是否要在商户系统下单,看商户需求  createBill()
        paramsMap.put("requestTimestamp", DateUtil.now());
        paramsMap.put("signType", "SHA256");
        //  增加回调地址
        paramsMap.put("notifyUrl", unionPay.getNotifyUrl());

        paramsMap.put("sign", UnionPayUtils.makeSign(unionPay.getCommunicationKey(), paramsMap));
        System.out.println("paramsMap:" + paramsMap);

        String strReqJsonStr = JSON.toJSONString(paramsMap);
        System.out.println("strReqJsonStr:" + strReqJsonStr);

        //  发送下单请求
        String result = HttpRequest.post(unionPay.getGateway()).body(JSONUtil.toJsonStr(paramsMap)).execute().body();
        final JSONObject resultJsonObj = JSONUtil.parseObj(result);
        System.out.println("resultJsonObj:" + resultJsonObj.toString());
        if (!"SUCCESS".equals(resultJsonObj.get("errCode"))) {
            throw new BusinessErrorProblem("银联下单失败!");
        }
        final JSONObject miniPayRequest = JSONUtil.parseObj(resultJsonObj.get("miniPayRequest"));
        return MicroPayVo.builder()
                .signType(miniPayRequest.get("signType").toString())
                .packageStr(miniPayRequest.get("package").toString()).timeStamp(miniPayRequest.get("timeStamp").toString())
                .nonceStr(miniPayRequest.get("nonceStr").toString()).paySign(miniPayRequest.get("paySign").toString())
                .build();
    }
}

![image.png](https://img-blog.csdnimg.cn/img_convert/87da51023b2c9b24fde4488f7a39dc89.png#clientId=uc8e1848f-6acb-4&from=paste&height=594&id=uf2710a2d&margin=[object Object]&name=image.png&originHeight=594&originWidth=1313&originalType=binary&ratio=1&size=440028&status=done&style=none&taskId=u3d4ce21d-3ad6-44ac-af57-f1174f08d52&width=1313)

注意点1:Hutool的工具类请求发送

String result = HttpRequest._post_**_(_**unionPay.getGateway**_())_**.body**_(_**JSONUtil._toJsonStr_**_(_**paramsMap**_))_**.execute**_()_**.body**_()_**;
这里需要注意的是:post请求,如果要把参数放在body中,需要使用HttpRequest,而不能使用HttpUtil。参数传递的时候,paramsMap是一个map,这边如果要把map转json字符串,需要使用JSONUtil去转换。不能通过Strings.valueOf这类的进行转换。

注意点2:下单请求传给微信支付部分signType问题

微信小程序调起支付API
微信小程序支付,调起支付Api的时候,signType为MD5,但是银联微信支付的时候signTyp为RSA。这里需要动态传递给前端。
![image.png](https://img-blog.csdnimg.cn/img_convert/e80d460c78558ecf5508dcbe596ad179.png#clientId=u80c99cc0-618d-4&from=paste&height=535&id=ua20bbb7a&margin=[object Object]&name=image.png&originHeight=535&originWidth=1018&originalType=binary&ratio=1&size=52669&status=done&style=none&taskId=u740b6f78-c888-4da0-9a27-3d3a1e179ca&width=1018)
![image.png](https://img-blog.csdnimg.cn/img_convert/2f8e665a78476219ba36d803b2b8cc83.png#clientId=u80c99cc0-618d-4&from=paste&height=333&id=u385e5b3b&margin=[object Object]&name=image.png&originHeight=333&originWidth=989&originalType=binary&ratio=1&size=90493&status=done&style=none&taskId=u966eafe4-ae6b-4647-9a96-4e9df2b30c5&width=989)

5、退款

![image.png](https://img-blog.csdnimg.cn/img_convert/6b7d851b2742e7b993ef5cfcb28a225b.png#clientId=ud43ca84c-7dae-4&from=paste&height=770&id=EFZJB&margin=[object Object]&name=image.png&originHeight=770&originWidth=807&originalType=binary&ratio=1&size=338842&status=done&style=none&taskId=u50dc4c8d-c10a-4a7b-b8ac-5694ebb0dd6&width=807)

注意点1:请求发起IP绑定白名单

这里需要注意的是,退款请求发起的服务器的公网IP,需要配置到银联的IP白名单中,不然会报错。

前端部分(uniapp)

apiChargePay(chargeData).then(res => {
    uni.hideLoading()
        let orderId = res.data.orderId
        let orderPayId = res.data.orderPayId
        let timeStamp = res.data.timeStamp
        let nonceStr = res.data.nonceStr
        let pk = res.data.package
        let paySign = res.data.paySign
        let signType = res.data.signType
        let _this = this

        if (nonceStr == null) {
            //	跳转到充电中页面
            this.redirectToChargeingPage(orderId, orderPayId)
                return
            }

    //用户微信端确认支付,执行支付操作
    uni.requestPayment({
        "timeStamp": timeStamp,
        "nonceStr": nonceStr,
        "signType": signType,
        "package": pk,
        "paySign": paySign,
        success: (res) => {
            //	用户支付后,跳转到充电中的页面O
            this.redirectToChargeingPage(orderId, orderPayId)
            },
        fail: (err) => {
            uni.showToast({
                icon: 'none',
                title: "支付失败"
                })
                //	取消订单的问题。
                apiDeleteChargeOrder(orderId)
            }
    })
})

下单成功消息通知

微信下单成功消息通知

![image.png](https://img-blog.csdnimg.cn/img_convert/b6c5b2bad1c1967a53a94f8a489a9820.png#clientId=ub5b999ef-cc3b-4&from=paste&height=776&id=ue2d89fe9&margin=[object Object]&name=image.png&originHeight=776&originWidth=1136&originalType=binary&ratio=1&size=447560&status=done&style=none&taskId=u269992d0-b702-4a6d-8bf2-0417cab5397&width=1136)

支付宝下单成功消息通知

![image.png](https://img-blog.csdnimg.cn/img_convert/b86e4bf0c45e61f3d6746d41e57c3f1e.png#clientId=uc8e1848f-6acb-4&from=paste&height=758&id=uf9bfc82b&margin=[object Object]&name=image.png&originHeight=758&originWidth=1101&originalType=binary&ratio=1&size=488458&status=done&style=none&taskId=u813e5925-65cd-48a9-9278-309d946c7a5&width=1101)

测试

由于测试需要在手机上展示,暂不放测试效果图了。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值