IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 微信建行支付对接 -> 正文阅读

[移动开发]微信建行支付对接

作者:recommend-item-box type_blog clearfix

参考链接一 微信小程序使用建行支付
参考链接二 微信小程序,调用建行支付
参开链接三 集成建行聚合支付踩过的坑,有些槽不吐不快

这里我也得吐槽一下,2022年了 建行的回调验签居然还是把jar自己导入到本次仓库进行依赖添加,居然没有上传自己的pom依赖,jdk还是1.5的。。。还是说有新的,我不知道?

微信支付使用建行流程

  1. 拼接建行链接,链接包括建行参数跟mac(字段MD5信息) post请求
  2. 请求后 建行返回字段中包含 一个链接,再次请求返回支付信息

例:
通过 POST 方式 第一次请求 字段信息是建行等配置

https://ibsbjstar.ccb.com.cn/CCBIS/ccbMainCCB_IBSVersion=V6&MERCHANTID=105320148140002&POSID=100001135&BRANCHID=320000000&ORDERID=88487&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=&REMARK2=&TYPE=1&GATEWAY=0&CLIENTIP=128.128.80.125&REGINFO=xiaofeixia&PROINFO=digital&REFERER=&SMERID=111&SMERNAME=%u5DE5%u827A%u7F8E%u672F%u5546%u5E97&SMERTYPEID=112&SMERTYPE=%u5BBE%u9986%u9910%u5A31%u7C7B&TRADECODE=001&TRADENAME=%u6D88%u8D39&SMEPROTYPE=1&PRONAME=%u5DE5%u827A%u54C1&TIMEOUT=20161028101226&TRADE_TYPE=MINIPRO&SUB_APPID=wx8888888888888888&SUB_OPENID=oUpF8uMuAJO_M2pxb1Q9zNjWeS6o&WX_CHANNELID=wx902937628837&USERPARAM=1U2xb%2FdMepRIs0KcM53xns%2Chdg2xBh3qwJ%2F%2F%2FHi%2FjMfPcbUYjQdxJKe%2CnoHnBgXppyQqPVPdDf8p%0D%0AEwxoLdkWjvdj2QUXJ5Hb&RETURN_FIELD=10000000000000000000&MAC=b2a1adfc9f9a44b57731440e31710740

请求后 返回信息

{
  "SUCCESS": "true",
  "PAYURL": "https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_02?CCB_IBSVersion=V6&MERCHANTID=105320148140002&POSID=100001135&BRANCHID=320000000&ORDERID=88487&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=&REMARK2=&TYPE=1&GATEWAY=0&CLIENTIP=128.128.80.125&REGINFO=xiaofeixia&PROINFO=digital&REFERER=&SMERID=111&SMERNAME=%u5DE5%u827A%u7F8E%u672F%u5546%u5E97&SMERTYPEID=112&SMERTYPE=%u5BBE%u9986%u9910%u5A31%u7C7B&TRADECODE=001&TRADENAME=%u6D88%u8D39&SMEPROTYPE=1&PRONAME=%u5DE5%u827A%u54C1&TIMEOUT=20161028101226&TRADE_TYPE=MINIPRO&SUB_APPID=wx8888888888888888&SUB_OPENID=oUpF8uMuAJO_M2pxb1Q9zNjWeS6o&MAC=b2a1adfc9f9a44b57731440e31710740&QRCODE=1&CHANNEL=1"
}

获取 PAYURL链接 再次请求

https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_02?CCB_IBSVersion=V6&MERCHANTID=105320148140002&POSID=100001135&BRANCHID=320000000&ORDERID=88487&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=&REMARK2=&TYPE=1&GATEWAY=0&CLIENTIP=128.128.80.125&REGINFO=xiaofeixia&PROINFO=digital&REFERER=&SMERID=111&SMERNAME=%u5DE5%u827A%u7F8E%u672F%u5546%u5E97&SMERTYPEID=112&SMERTYPE=%u5BBE%u9986%u9910%u5A31%u7C7B&TRADECODE=001&TRADENAME=%u6D88%u8D39&SMEPROTYPE=1&PRONAME=%u5DE5%u827A%u54C1&TIMEOUT=20161028101226&TRADE_TYPE=MINIPRO&SUB_APPID=wx8888888888888888&SUB_OPENID=oUpF8uMuAJO_M2pxb1Q9zNjWeS6o&MAC=b2a1adfc9f9a44b57731440e31710740&QRCODE=1&CHANNEL=1

此时返回 请求结果

{
"appId": "wxad35f06adfdsgre3" 
"errcode": "000000"
"errmsg": ""
"mweb_url": ""
"mypackage": "prepay_id=wx15155254732131244559e3cb82f0000"
"nonceStr": "wYggZEgyfdfdsfasdsaJpPOSw61sG"
"partnerid": "54523121"
"paySign": "Hn/e4XM7gOnfhADoN6ccVh2BnAX09zs2IjlqPs5PfckIkUXFRSwprCd9g94FU4NwoZd58tjtwFjiI/7z2qaXhMwNKlxthjgasavUWhhHd3Nb1JPIORiRXlN/lyElmDj4RQ/6+bheixrQmT7NlIX/gCcpRxJbIw+lmoNMbgJWB8nNZ4YOIkS8B9ybBjluNa4bqePwKxSfLJnDJmlm95IDIVcJ/+uuTED97peHPbEI39t966wFbibXxUi6cbeOtYieW7TkwDIt3LGX6SqvLlMybXDyuKGseyY0wG80UNOFShvOt60iFiFJhAuE0OXHFw=="
"prepayid": ""
"signType": "RSA"
"success": true
"timeStamp": "1605426774"
"txcode": "530590"
}

参数介绍

字段名称说明
SUCCESS返回状态码此字段是通信标识,表示通信成功
ERRCODE错误码000000表示交易成功,非000000表示交易失败,错误信息可以查看ERRMSG字段
ERRMSG错误信息错误信息描述
TXCODE交易码530590
appId微信分配的APPID参考微信对应的调起支付API
timeStamp时间戳参考微信对应的调起支付API
nonceStr随机串参考微信对应的调起支付API
package数据包参考微信对应的调起支付API
signType签名方式参考微信对应的调起支付API
paySign签名数据参考微信对应的调起支付API
partnerid子商户的商户号参考微信对应的调起支付API
prepayid预支付交易会话ID参考微信对应的调起支付API
mweb_url微信H5支付中间页面URL参考微信对应的调起支付API

建行请求流程图

可能会遇到的问题

  1. MAC校验失败, 可能是加密字段顺序不一致
  2. “ERRMSG”:“支付不成功,@@INVALID_REQUEST~~sub_mch_id与sub_appid不匹配@@”, 没有配置商户id绑定

商户使用小程序

重点
拼接建行md5加密 字段是有顺序的,不然请求后会返回mac校验失败,PUB(公钥后三十位)字段只参与加密,不参与参数传递

例: 加密字段有PUB字段,请求不需要加 PUB字段, MAC是加密信息md5后的信息

加密字段
MERCHANTID=0000&POSID=0000&BRANCHID=0000&ORDERID=0000&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=2&REMARK2=&TYPE=1&PUB=0000&GATEWAY=0&CLIENTIP=192.168.56.1&REGINFO=&PROINFO=&REFERER=&TRADE_TYPE=JSAPI&SUB_APPID=0000&SUB_OPENID=0000

建行请求链接
https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6&MERCHANTID=0000&POSID=0000&BRANCHID=0000&ORDERID=0000&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=2&REMARK2=&TYPE=1&GATEWAY=0&CLIENTIP=192.168.56.1&REGINFO=&PROINFO=&REFERER=&TRADE_TYPE=JSAPI&SUB_APPID=0000&SUB_OPENID=0000&MAC=md5加密字信息

开发前置准备

  1. md5加密使用的是hutool工具集的 SecureUtil.md5() 方法 添加依赖即可 hutool工具集
  2. 建行jar包,以供调用接口回调验签
  3. 配置微信小程序信息 可以使用 wx-java 小程序用小程序的依赖,公众号用公众号的依赖 公众号配置 小程序配置

本地jar包导入命令

mvn install:install-file "-Dfile=F:\work\java\ccb\netpay.jar" "-DgroupId=CCBSign" "-DartifactId=RSASig" "-Dversion=1.0" "-Dpackaging=jar"

导入到本地仓库后添加到pom文件

<dependency>
   <groupId>CCBSign</groupId>
   <artifactId>RSASig</artifactId>
   <version>1.0</version>
</dependency>

建行开发

mac 加密的字段及顺序

$host = 'https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6&';
$string = 'MERCHANTID=00000&POSID=0000&BRANCHID=000&ORDERID=0000&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=&REMARK2=&TYPE=1&PUB=00000000&GATEWAY=0&CLIENTIP=127.0.0.1&REGINFO=&PROINFO=%u94bb%u77f3%u4f1a%u5458%u4f18%u60E0%u5927%u4fC3&REFERER=&TRADE_TYPE=MINIPRO&SUB_APPID=0000&SUB_OPENID=0000';
echo $host.$string."&MAC=".md5($string);

流程看的差不多了,接下来就是对接建行。
如何拼接建行请求字段以及如何拼接生成md5信息,这里提供两种方式

  1. 实体类定义字段,通过反射拼接字符串
  2. 通过map、append拼接字符串

拼接建行请求链接

方式一 利用反射拼接

基础配置

  1. 可以定义在常量类中 直接写死
  2. 我这里写在配置类里进行了读取
    两种方式都可以

yml配置属性

ccb:
  url: https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6
  merchant-id:  你的建行商户id
  pos-id: '你的建行posid'     # 这里使用单引号是因为前面如果是0的话 读取过去会去掉
  branch-id: 你的建行branch-id
  cur-code: '01'
  tx-code: 530590
  gateway: 0
  type: 1
  pub: 公钥后三十位

yml配置类

/**
 * 建行url属性
 *
 * @author Administrator
 * @date 2022/07/28
 */
@Data
@Component
@ConfigurationProperties(prefix = "ccb")
public class CcbProperties {
    /**
     * 建行支付请求连接
     */
    private String url;
    /**
     * 商户代码
     */
    private String merchantId;
    /**
     * 商户柜台代码
     */
    private String posId;
    /**
     * BRANCHID
     */
    private String branchId;
    /**
     * 币种类型 01 人民币
     */
    private String curCode;
    /**
     * 交易码 由建行统一分配为530590
     */
    private String txCode;
    /**
     * 网关 默认0
     */
    private String gateway;
    /**
     * 接口类型 1- 防钓鱼接口
     */
    private String type;
    /**
     * 公钥后三十位
     */
    private String pub;

}

参与加密的字段及顺序 实体类展现

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CcbTakeMacReq {

    /**
     *  商户代码
     */
    private String MERCHANTID;
    /**
     * 商户柜台代码
     */
    private String POSID;
    /**
     * 分行代码
     */
    private String BRANCHID;
    /**
     * 定单号 由商户提供,最长30位
     */
    private String ORDERID;
    /**
     *  付款金额 由商户提供,按实际金额给出
     */
    private String PAYMENT;
    /**
     * 币种 缺省为01-人民币
     * (只支持人民币支付)
     */
    private String CURCODE;
    /**
     *  交易码
     */
    private String TXCODE;

    /**
     *  备注1 一般作为商户自定义备注信息使用,可在对账单中显示。
     */
    private String REMARK1;
    /**
     *  备注2 一般作为商户自定义备注信息使用,可在对账单中显示。
     */
    private String REMARK2;

    /**
     *  接口类型 分行业务人员在P2员工渠道后台设置防钓鱼的开关。
     * 1-	防钓鱼接口
     */
    private String TYPE;
    /**
     *  公钥后30位 商户从建行商户服务平台下载,截取后30位。
     * 仅作为源串参加MD5摘要,不作为参数传递
     */
    private String PUB;
    /**
     *  网关类型 默认送0
     */
    private String GATEWAY;
    /**
     *  客户端IP 客户在商户系统中的IP,即客户登陆(访问)商户系统时使用的ip)
     */
    private String CLIENTIP;
    /**
     *  客户注册信息  客户在商户系统中注册的信息,中文需使用escape编码
     */
    private String REGINFO;
    /**
     * 商品信息 客户购买的商品
     * 中文需使用escape编码
     */
    private String PROINFO;
    /**
     * 商户URL 商户送空值即可;
     * 具体请看REFERER设置说明
     */
    private String REFERER;

    /**
     * 交易类型 JSAPI--公众号支付、APP--app支付、MINIPRO--小程序、H5--H5跳转支付
     * @see WxPayEnum
     */
    private String TRADE_TYPE;
    /**
     * 当前调起支付的小程序APPID
     */
    private String SUB_APPID;
    /**
     * 用户在小程序appid下的唯一标识,小程序通过wx.login获取
     */
    private String SUB_OPENID;

}

反射工具类

@Component
public class FiledConvertUtils {

    /**
     * 获取对象的所有字段名和字段值
     *
     * @param object
     * @return
     */
    public static String getFieldNameAndValue(Object object) {
        List<String> values = Lists.newArrayList();
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                if("PUB".equalsIgnoreCase( field.getName())) {
                    continue;
                }
                values.add(String.format("%s=%s", field.getName(), (null == field.get(object)) ? "" : field.get(object)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String value = String.join("&", values);
        return value;
    }

	// 获取md5加密字段
    public static String getMd5(Object object) {
        List<String> values = Lists.newArrayList();
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                values.add(String.format("%s=%s", field.getName(), (null == field.get(object)) ? "" : field.get(object)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String value = String.join("&", values);
        System.out.println("加密字符串" + value);
        return String.format("&MAC=%s", SecureUtil.md5(value));
    }




    @Autowired
    private CcbProperties ccbProperties;

    
	// 对数据进行赋值
    public void toCcbMacSetting(CcbTakeMacReq macReq) {
        macReq.setMERCHANTID(ccbProperties.getMerchantId());
        macReq.setPOSID(ccbProperties.getPosId());
        macReq.setBRANCHID(ccbProperties.getBranchId());
        macReq.setCURCODE(ccbProperties.getCurCode());
        macReq.setTXCODE(ccbProperties.getTxCode());
        macReq.setGATEWAY(ccbProperties.getGateway());
        macReq.setTYPE(ccbProperties.getType());
        macReq.setCLIENTIP(IpUtils.getHostIp());
        macReq.setTRADE_TYPE(TradeTypeEnum.JSAPI.name());
        macReq.setREFERER("");
    }

}

方式二 直接拼接

拼接工具类


@Component
@RequiredArgsConstructor
public class CcbParamUtils {
    

    private final CcbProperties ccbProperties;

    public String getPayRequestParam(String orderNo, BigDecimal payMoney, String openid, String appId) {
        //md5加密  MD5加密后生成32位(小写字母 + 数字)字符串
        String sb1 = "MERCHANTID=" + ccbProperties.getMerchantId() + "&" +
                "POSID=" + ccbProperties.getPosId() + "&" +
                "BRANCHID=" + ccbProperties.getBranchId() + "&" +
                "ORDERID=" + orderNo.trim() + "&" +
                "PAYMENT=" + payMoney + "&" +
                "CURCODE=" + ccbProperties.getCurCode() + "&" +
                "TXCODE=530590&" +
                "REMARK1=&REMARK2=&" +
                "TYPE=" + ccbProperties.getType() + "&" +
                "PUB=" + ccbProperties.getPub() + "&" +
                "GATEWAY=" + ccbProperties.getGateway() + "&" +
                "CLIENTIP=&REGINFO=&PROINFO=&REFERER=&" +
                "TRADE_TYPE=" + TradeTypeEnum.JSAPI.name() + "&" +
                "SUB_APPID=" + appId + "&" +
                "SUB_OPENID=" + openid;
        String sb2 = "MERCHANTID=" + ccbProperties.getMerchantId() + "&" +
                "POSID=" + ccbProperties.getPosId() + "&" +
                "BRANCHID=" + ccbProperties.getBranchId() + "&" +
                "ORDERID=" + orderNo.trim() + "&" +
                "PAYMENT=" + payMoney + "&" +
                "CURCODE=" + ccbProperties.getCurCode() + "&" +
                "TXCODE=530590&" +
                "REMARK1=&REMARK2=&" +
                "TYPE=" + ccbProperties.getType() + "&" +
                "GATEWAY=" + ccbProperties.getGateway() + "&" +
                "CLIENTIP=&REGINFO=&PROINFO=&REFERER=&" +
                "TRADE_TYPE=" + TradeTypeEnum.JSAPI.name() + "&" +
                "SUB_APPID=" + appId + "&" +
                "SUB_OPENID=" + openid;
        return sb2 + "&MAC=" + SecureUtil.md5(sb1);
    }
}

请求返回链接 回去返回参数

回调方法

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 19:17:25  更:2022-08-19 19:19:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:37:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码