微信小程序使用建行支付

  • IT
  • JAVA
  • 支付
  • 小程序
  • java

一、交易流程说明

正在上传…重新上传取消

二、接口说明

字段 说明 类型 必传
MERCHANTID 商户代码,由建行统一分配 CHAR(15)
POSID 商户柜台代码,由建行统一分配 CHAR(9)
BRANCHID 分行代码,由建行统一分配 CHAR(9)
ORDERID 订单号,由商户提供,最长30位(数字) CHAR(30)
PAYMENT 付款金额,由商户提供,按实际金额给出。支付完成后,请商户与收到的商户通知中的付款金额比对,确认两者金额一致; NUMBER(16,2)
CURCODE 币种,缺省为01-人民币(目前只支持人民币支付) CHAR(2)
REMARK1 备注1,一般作为商户自定义备注信息使用,可在对账单中显示。集团主商户代理发起子商户交易时,需将集团主商户信息填入该字段,格式如下:JTSH:主商户号+主柜台例如:JTSH:105000000000000123456789其中105000000000000为主商户号,123456789为主柜台 CHAR(30)
REMARK2 备注2,一般作为商户自定义备注信息使用,可在对账单中显示。 CHAR(30)
TXCODE 交易码,由建行统一分配 ,为530590 CHAR(6)
MAC MAC校验域,采用标准MD5算法,由商户实现 CHAR(32)
TYPE 接口类型,分行业务人员在P2员工渠道后台设置防钓鱼的开关。1-防钓鱼接口 CHAR(1)
PUB 公钥后30位,商户从建行商户服务平台下载,截取后30位。仅作为源串参加MD5摘要,不作为参数传递 CHAR(30)
GATEWAY 网关类型,默认为0 VARCHAR(100)
CLIENTIP 客户端IP,客户在商户系统中的IP,即客户登陆(访问)商户系统时使用的ip) CHAR(40)
REGINFO 客户注册信息,客户在商户系统中注册的信息,中文需使用escape编码 CHAR(256)
PROINFO 商品信息,客户购买的商品中文需使用escape编码 CHAR(256)
REFERER 商户URL,商户送空值即可;具体请看REFERER设置说明 CHAR(100)
TIMEOUT 订单超时时间,格式:YYYYMMDDHHMMSS如:20120214143005银行系统时间> TIMEOUT时拒绝交易,若送空值则不判断超时。当该字段有值时参与MAC校验,否则不参与MAC校验。 CHAR(14)
TRADE_TYPE 交易类型,JSAPI–公众号支付、MINIPRO–小程序 CHAR(16)
SUB_APPID 小程序/公众号的APPID,当前调起支付的小程序/公众号APPID CHAR(32)
SUB_OPENID 用户子标识用户在小程序/公众号appid下的唯一标识,小程序通过wx.login获取,接口文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html?t=20161122 CHAR(128)
WX_CHANNELID 渠道商号,对于商户自定义的渠道商号当该字段有值时参与MAC校验,否则不参与MAC校验。 CHAR(20)
RETURN_FIELD 返回信息位图,共20位,商户通知是否返回某个字段的位图,0或空-不返回,1-返回。第1位:是否返回OPENID和SUB_OPENID第2位:保留位,默认送0第3位:保留位,默认送0 第4位:是否返回支付详细信息字段示例:10000000000000000000 CHAR(20)
USERPARAM 实名支付,实名支付功能,包含类型、证件号、姓名三个子域(如果本字段出现,那么本字段包含的三个子域均需出现。详见下文说明5)USERPARAM字段说明)。当该字段有值时参与MAC校验,否则不参与MAC校验。暂未上线,请忽略 VARCHAR(2000)

二级商户信息

若上送二级商户信息则八个二级商户信息字段必须都送值,当该字段有值时参与MAC校验,否则不参与MAC校验。

字段 说明 类型 必传
SMERID 二级商户代码,由建行统一分配 CHAR(15)
SMERNAME 二级商户名称,中文需使用escape编码 中文(33)、英文CHAR(100)
SMERTYPEID 二级商户类别代码 CHAR(15)
SMERTYPE 二级商户类别名称,汉字最长27个,中文需使用escape编码 中文(27)、英文CHAR(81)
TRADECODE 交易类型代码 CHAR(15)
TRADENAME 交易类型名称,如消费、投资理财、信用卡还款等,中文需使用escape编码 中文(10),英文CHAR(30)
SMEPROTYPE 商品类别代码 CHAR(24)
PRONAME 商品类别名称,中文需使用escape编码 中文(15)英文CHAR(50)

注:字符串中变量名必须是大写字母。
1)参与摘要运算的字符串及其顺序如下:
请注意:加粗的字段请根据需要上送,有值时才参与MAC,否则无需参与MAC。
MERCHANTID=123456789&POSID=000000000&BRANCHID=110000000&ORDERID=19991101234&PAYMENT=0.01&CURCODE=01&TXCODE=530590&REMARK1=&REMARK2=&TYPE=1&PUB=30819d300d06092a864886f70d0108&GATEWAY=0&CLIENTIP=172.0.0.1®INFO=%u5C0F%u98DE%u4FA0&PROINFO=%u5145%u503C%u5361&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

2)使用js的escape()方法对“客户注册信息”和“商品信息”进行转码,数字字母信息不需转码。
例:escape(小飞侠)= %u5C0F%u98DE%u4FA0
escape(充值卡)= %u5145%u503C%u5361

3)使用js的escape()方法对“二级商户名称”、“二级商户类别名称”、“交易类型名称”、“商品类别名称”进行转码,数字字母信息不需转码。
例: escape (工艺美术商店)=%u5DE5%u827A%u7F8E%u672F%u5546%u5E97
escape (宾馆餐娱类)= %u5BBE%u9986%u9910%u5A31%u7C7B
escape (消费)= %u6D88%u8D39
escape (工艺品)= %u5DE5%u827A%u54C1

4)完整的URL:
第三方商户提交给网银的网关地址:注意用post方式提交参数。
https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6
请注意:加粗的字段请根据需要上送
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®INFO=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

5)访问上述请求后,获得数据
{“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®INFO=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” }

6)使用GET请求,直接访问PAYURL中的地址

7)获得JSON数据,

{"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

三、微信相关调起API链接

小程序:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=7_7&index=5
公众号:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=7_7&index=6

四、支付反馈地址设置(回调地址)

说明:反馈地址,就是支付完成后,建行会向你设置的反馈地址发送信息,类似纯微信支付的反馈地址。

信息里面会有ORDERID(订单号)与PAYMENT(字符金额),当然还有其他的信息。一般会在反馈的处理方法里面进行金额校验与修改订状态的操作

方法1:商户后台设置

正在上传…重新上传取消

方法2:访问开发接口

查阅接口文档
建行开放接口文档

项目中遇到的有关反馈的问题

反馈地址这一块相对来说是比较难调试,也会遇到很多问题。我就说一下我遇到的问题以及我是如何解决的。
在测试版本(测试版本使用的反馈地址的协议是http)测试时,可正常接收到建行发送过来的反馈信息。但是切换到正式版本(正式版本使用的反馈地址的协议是https)后,发现支付完成后怎么都接收不到建行的反馈信息,建行那边查询原因后说是向反馈地址发送请求后返回的是403(服务器禁止访问),尝试了很多种方法,最后是通过开启springboot项目的双协议配置,即项目可同时通过http协议与https协议进行访问(不同协议端口不一致),回调地址使用的是http协议的。这是退而求其次的方法,这个问题并没有完全解决,今后如果找到解决方法,会更新博客。哪位大佬彻底解决了这个问题,也欢迎分享。
springboot开启双协议的配置

五、访问建行开发接口

建行开放接口文档

1. 商户反馈地址查询(示例,其他的接口都类似)

1)请求地址:http://120.77.236.53:9999

2)请求参数


<TX>  <REQUEST_SN>请求序列号REQUEST_SN>  <CUST_ID>商户号CUST_ID>  <USER_ID>操作员号USER_ID>  <PASSWORD>操作员号密码PASSWORD>  <TX_CODE>5W1019TX_CODE>  <LANGUAGE>CNLANGUAGE>  <TX_INFO>  <POS_ID>终端编号POS_ID>  TX_INFO>
TX>

3)响应信息

   <TX>  <REQUEST_SN>请求序列码REQUEST_SN>   <CUST_ID>商户号CUST_ID>   <TX_CODE>5W1019TX_CODE>   <RETURN_CODE>响应码RETURN_CODE>   <RETURN_MSG>响应信息RETURN_MSG>  <LANGUAGE>CNLANGUAGE>  <TX_INFO>  <POS_ACCDATE_FLAG>是否返回记账日期POS_ACCDATE_FLAG>   <LIST>  <EC_CgyCd>电子渠道类别代码EC_CgyCd>   <Rsrv_Fld_1>网页反馈地址Rsrv_Fld_1>   <Rsrv_Fld_2>服务器反馈地址Rsrv_Fld_2>   <Rsrv_Fld_3>实时反馈标志Rsrv_Fld_3>   LIST>  <NOTICE>提示信息NOTICE>  TX_INFO>  TX>

正在上传…重新上传取消

4)Springboot使用RestTemplate请求实例

public Response test(){RestTemplate restTemplate = new RestTemplateBuilder().build();String urlXML ="" +"" +"" + KeyUtil.uniqueKey() + "" +"" + "" + "" +"" + "" + "" +"" + "" + "" +"" + "5W1019" + "" +"" + "CN"+ "" +"" +"" + "" + "" +"" +"";String params = null;params = "requestXml=" + urlXML;String parameter = params;HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<String> requestEntity = new HttpEntity<String>(parameter, headers);ResponseEntity<String> response = restTemplate.exchange("http://120.77.236.53:9999", HttpMethod.POST, requestEntity, String.class);return Response.success(response.getBody());}

六、Demo项目代码

1.服务层接口

import java.math.BigDecimal;/*** 建行支付服务类*/
public interface JHPayService {/*** 发起支付* @param orderNo 订单号* @param payMoney 支付金额* @param openid 微信用户openid* @param appId 微信小程序appId* @return*/JHPayResult JHPay(String orderNo, BigDecimal payMoney, String openid, String appId);/*** 发起退款* @param orderNo 订单号* @param refundMoney 退款金额* @param payMoney 支付金额* @return*/JHRefundResponse JHRefund(String orderNo, BigDecimal refundMoney, BigDecimal payMoney);
}

2.服务层实现

import com.google.gson.Gson;
import com.zengmi.config.JHPayProperties;
import com.zengmi.enums.ErrorEnum;
import com.zengmi.exception.MyException;
import com.zengmi.utils.KeyUtil;
import com.zengmi.utils.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;import java.math.BigDecimal;
import java.util.Date;/*** 建行支付退款服务层* @author IT00ZYQ* @Date 2020/10/22 19:14**/
@Service
@Slf4j
public class JHPayServiceImpl implements JHPayService{private static final String successCode = "000000";@Autowiredprivate JHPayProperties jhPayProperties;@Autowiredprivate RestTemplate restTemplate;@Overridepublic JHPayResult JHPay(String orderNo, BigDecimal payMoney, String openid, String appId) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<String> requestEntity = new HttpEntity<>(getPayRequestParam(orderNo, payMoney, openid, appId), headers);//POST方式访问网银获取PAYURLResponseEntity<String> response = restTemplate.exchange(jhPayProperties.getURL(), HttpMethod.POST, requestEntity, String.class);HttpEntity<String> requestEntity2 = new HttpEntity<>("", headers);JHPayDTO dto = new Gson().fromJson(response.getBody(), JHPayDTO.class);//GET方式访问PAYURL获取唤起微信支付的参数ResponseEntity<String> response2 = restTemplate.exchange(dto.getPayUrl(), HttpMethod.GET, requestEntity2, String.class);//将json字符串转化为WxPayment对象JHPayResult result = new Gson().fromJson(response2.getBody(), JHPayResult.class);result.setOrderNo(orderNo);return result;}@Overridepublic JHRefundResponse JHRefund(String orderNo, BigDecimal refundMoney, BigDecimal payMoney) {if (refundMoney.compareTo(payMoney) > 0 ){throw new MyException(ErrorEnum.REFUND_MONEY_HAVE_ERROR);}log.info("【进入建行退款】订单号:{}, 退款金额:{}, 时间:{}", orderNo, refundMoney, new Date());//请求外联HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<String> requestEntity = new HttpEntity<String>(getRefundRequestXml(orderNo, refundMoney), headers);System.out.println(requestEntity);ResponseEntity<String> response = this.restTemplate.exchange(jhPayProperties.getREFUND_URL(),HttpMethod.POST,requestEntity,String.class);if (ObjectUtils.isEmpty(response) || ObjectUtils.isEmpty(response.getBody())){throw new MyException(ErrorEnum.REFUND_REQUEST_ERROR);}String str = response.getBody();log.info("【建行退款返回信息】:{}", str);//分割得到返回信息String code = str.substring(str.indexOf("")+13, str.lastIndexOf(""));if (successCode.equals(code)){return JHRefundResponse.builder().orderNo(str.substring(str.indexOf("") + 11, str.lastIndexOf(""))).payMoney(new BigDecimal(str.substring(str.indexOf("") + 12, str.lastIndexOf("")))).refundMoney(new BigDecimal(str.substring(str.indexOf("") + 8, str.lastIndexOf("")))).success(true).build();}else {throw new MyException(ErrorEnum.REFUND_ERROR);}}/*** 建行支付请求参数处理* @param orderNo* @param payMoney* @param openid* @param appId* @return*/private String getPayRequestParam(String orderNo, BigDecimal payMoney, String openid, String appId) {//md5加密  MD5加密后生成32位(小写字母 + 数字)字符串String sb1 = "MERCHANTID=" + jhPayProperties.getMERCHANTID() + "&" +"POSID=" + jhPayProperties.getPOSID() + "&" +"BRANCHID=" + jhPayProperties.getBRANCHID() + "&" +"ORDERID=" + orderNo.trim() + "&" +"PAYMENT=" + payMoney + "&" +"CURCODE=" + jhPayProperties.getCURCODE() + "&" +"TXCODE=530590&" +"REMARK1=&REMARK2=&" +"TYPE=" + jhPayProperties.getTYPE() + "&" +"PUB=" + jhPayProperties.getPUB() + "&" +"GATEWAY=" + jhPayProperties.getGATEWAY() + "&" +"CLIENTIP=®INFO=&PROINFO=&REFERER=&" +"TRADE_TYPE=" + jhPayProperties.getTRADE_TYPE() + "&" +"SUB_APPID=" + appId + "&" +"SUB_OPENID=" + openid;String sb2 = "MERCHANTID=" + jhPayProperties.getMERCHANTID() + "&" +"POSID=" + jhPayProperties.getPOSID() + "&" +"BRANCHID=" + jhPayProperties.getBRANCHID() + "&" +"ORDERID=" + orderNo.trim() + "&" +"PAYMENT=" + payMoney + "&" +"CURCODE=" + jhPayProperties.getCURCODE() + "&" +"TXCODE=530590&" +"REMARK1=&REMARK2=&" +"TYPE=" + jhPayProperties.getTYPE() + "&" +"GATEWAY=" + jhPayProperties.getGATEWAY() + "&" +"CLIENTIP=®INFO=&PROINFO=&REFERER=&" +"TRADE_TYPE=" + jhPayProperties.getTRADE_TYPE() + "&" +"SUB_APPID=" + appId + "&" +"SUB_OPENID=" + openid;return sb2 + "&MAC=" + MD5Util.MD5Lower(sb1);}/*** 建行退款请求参数处理* @param orderNo* @param refundMoney* @return*/private String getRefundRequestXml(String orderNo, BigDecimal refundMoney){//请求序列号String requestSN = KeyUtil.uniqueKey();StringBuffer sb = new StringBuffer();sb.append("requestXml=").append("").append("").append("").append(requestSN).append("").append("").append(jhPayProperties.getCUST_ID()).append("").append("").append(jhPayProperties.getUSER_ID()).append("").append("").append(jhPayProperties.getPASSWORD()).append("").append("").append("5W1004").append("").append("").append(jhPayProperties.getLANGUAGE()).append("").append("").append("").append(refundMoney).append("").append("").append(orderNo).append("").append("").append("").append("").append("").append("");return sb.toString();}
}

3.MD5工具类

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;public class MD5Util {static final char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};static final char[] hexDigitsLower = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};public static String makeMD5(String password) {String result = null;MessageDigest messageDigest;try {messageDigest = MessageDigest.getInstance("MD5");messageDigest.update(password.getBytes());result = new BigInteger(1, messageDigest.digest()).toString(16);} catch (Exception e) {e.printStackTrace();}return result;}/*** 对字符串 MD5 无盐值加密** @param plainText 传入要加密的字符串* @return MD5加密后生成32位(小写字母 + 数字)字符串*/public static String MD5Lower(String plainText) {try {// 获得MD5摘要算法的 MessageDigest 对象MessageDigest md = MessageDigest.getInstance("MD5");// 使用指定的字节更新摘要md.update(plainText.getBytes());// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值return new BigInteger(1, md.digest()).toString(16);} catch (NoSuchAlgorithmException e) {e.printStackTrace();return null;}}/*** 对字符串 MD5 加密** @param plainText 传入要加密的字符串* @return MD5加密后生成32位(大写字母 + 数字)字符串*/public static String MD5Upper(String plainText) {try {// 获得MD5摘要算法的 MessageDigest 对象MessageDigest md = MessageDigest.getInstance("MD5");// 使用指定的字节更新摘要md.update(plainText.getBytes());// 获得密文byte[] mdResult = md.digest();// 把密文转换成十六进制的字符串形式int j = mdResult.length;char str[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = mdResult[i];str[k++] = hexDigits[byte0 >>> 4 & 0xf];// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换}return new String(str);} catch (Exception e) {e.printStackTrace();return null;}}/*** 对字符串 MD5 加盐值加密** @param plainText 传入要加密的字符串* @param saltValue 传入要加的盐值* @return MD5加密后生成32位(小写字母 + 数字)字符串*/public static String MD5Lower(String plainText, String saltValue) {try {// 获得MD5摘要算法的 MessageDigest 对象MessageDigest md = MessageDigest.getInstance("MD5");// 使用指定的字节更新摘要md.update(plainText.getBytes());md.update(saltValue.getBytes());// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值return new BigInteger(1, md.digest()).toString(16);} catch (NoSuchAlgorithmException e) {e.printStackTrace();return null;}}/*** 对字符串 MD5 加盐值加密** @param plainText 传入要加密的字符串* @param saltValue 传入要加的盐值* @return MD5加密后生成32位(大写字母 + 数字)字符串*/public static String MD5Upper(String plainText, String saltValue) {try {// 获得MD5摘要算法的 MessageDigest 对象MessageDigest md = MessageDigest.getInstance("MD5");// 使用指定的字节更新摘要md.update(plainText.getBytes());md.update(saltValue.getBytes());// 获得密文byte[] mdResult = md.digest();// 把密文转换成十六进制的字符串形式int j = mdResult.length;char str[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = mdResult[i];str[k++] = hexDigits[byte0 >>> 4 & 0xf];str[k++] = hexDigits[byte0 & 0xf];}return new String(str);} catch (Exception e) {e.printStackTrace();return null;}}/*** MD5加密后生成32位(小写字母+数字)字符串* 同 MD5Lower() 一样*/public static String MD5(String plainText) {try {MessageDigest mdTemp = MessageDigest.getInstance("MD5");mdTemp.update(plainText.getBytes("UTF-8"));byte[] md = mdTemp.digest();int j = md.length;char str[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];str[k++] = hexDigitsLower[byte0 >>> 4 & 0xf];str[k++] = hexDigitsLower[byte0 & 0xf];}return new String(str);} catch (Exception e) {return null;}}/*** 校验MD5码** @param text 要校验的字符串* @param md5  md5值* @return 校验结果*/public static boolean valid(String text, String md5) {return md5.equals(MD5(text)) || md5.equals(Objects.requireNonNull(MD5(text)).toUpperCase());}}

4.参数封装类

1)访问网银接口返回封装类

import com.google.gson.annotations.SerializedName;
import lombok.Data;/*** @author IT00ZYQ* @Date 2020/11/13 10:36* PARURL封装类**/
@Data
public class JHPayDTO {@SerializedName("SUCCESS")private String success;@SerializedName("PAYURL")private String payUrl;}

2)建行返回封装对象

import com.google.gson.annotations.SerializedName;
import lombok.Data;import java.io.Serializable;/*** 建行返回参数封装对象*/
@Data
public class JHPayResult implements Serializable {/*** 此字段是通信标识,表示通信成功*/@SerializedName("SUCCESS")private boolean  success;/*** 000000表示交易成功,非000000表示交易失败,错误信息可以查看ERRMSG字段*/@SerializedName("ERRCODE")private String errcode;/**** 错误信息描述*/@SerializedName("ERRMSG")private String errmsg;/*** 交易码*/@SerializedName("TXCODE")private String txcode;/***微信分配的APPID*/private String appId;/*** 时间戳*/private String timeStamp;/*** 随机串*/private String nonceStr;/*** 数据包*/@SerializedName("package")private String Mypackage;/*** 签名方式*/private String signType;/*** 签名数据*/private String paySign;/*** 子商户的商户号*/private String partnerid;/*** 预支付交易会话ID 建行没有*/private String prepayid ;/*** 微信H5支付中间页面URL*/private String mweb_url;/*** 订单号*/private String orderNo;}

3)建行退款返回封装类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;/*** @author IT00ZYQ* @Date 2020/11/13 12:48* 建行退款返回封装类**/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class JHRefundResponse {/*** 是否成功退款,成功true,失败false*/private Boolean success;/*** 订单号*/private String orderNo;/*** 订单支付金额,单位元*/private BigDecimal payMoney;/*** 退款金额,单位元*/private BigDecimal refundMoney;}

5.获取唯一随机序列工具类

import java.util.Random;/*** @author IT00ZYQ* @Date 2020/5/25 18:02* 获取唯一序列工具类**/
public class KeyUtil {/*唯一键,当前毫秒数+三位随机数*/public static synchronized String uniqueKey(){Random random = new Random();Integer number = random.nextInt(900)+100;return System.currentTimeMillis()+String.valueOf(number);}/*唯一键,当前毫秒数后9位+三位随机数*/public static synchronized String uniqueKey2(){Random random = new Random();Integer number = random.nextInt(900)+100;return String.valueOf(System.currentTimeMillis()).substring(6)+String.valueOf(number);}
}

你可能感兴趣的

微信小程序使用建行支付相关推荐

  1. 微信小程序 openid及支付的若干问题解决方案

    微信小程序 openid及支付的若干问题解决方案 参考文章: (1)微信小程序 openid及支付的若干问题解决方案 (2)https://www.cnblogs.com/jhlqab/p/78500 ...

  2. 【SpringBoot学习】39、SpringBoot 集成 wxJava 微信小程序:订单支付

    文章目录 SpringBoot 集成 wxJava 微信小程序:订单支付 1.整合 wxJava 小程序 2.支付配置类 3.application.yml 配置 4.授权登录流程 5.uniapp ...

  3. 老板提了个需求:微信小程序调用支付宝支付!然后群里炸锅了

    大前天,我们头戴菊花手拿红包的小编同学在社群里发出了灵魂提问: (声明一下:小编同学只是在我这里兼职运营社群,人家正经工作还是产品狗.所以这个老板不是我) 这个问题简单说,就是在微信小程序里调用支付宝 ...

  4. 微信小程序怎么开通支付功能?

    对于一些想通过小程序卖货的企业商家来说,在申请小程序后需要同时开通微信支付功能,才能在小程序上进行交易.那么关于微信小程序怎么开通支付功能,下面给大家说一说. 一.注册非个人主体的小程序账号 不管你是 ...

  5. 微信小程序php后台支付,微信小程序 支付功能实现PHP实例详解

    微信小程序 支付功能实现PHP实例详解 前端代码: wx.request({ url: 'https://www.yourhost.com/weixin/WeiActivity/payJoinfee' ...

  6. 微信小程序开发笔记 支付篇③——微信支付JSAPI下单和微信小程序调起支付(V2版本)

    文章目录 一.前文 二.流程图 三.SpringBoot接口实现 2.1 微信调起支付所需数据 2.2 下单接口 2.3 支付回调接口 三.微信小程序实现 3.1 JSAP统一下单 3.2 小程序调起 ...

  7. 微信小程序订单生成支付二维码接口 code

    手机的小程序订单是直接拉起支付界面的,有些朋友需要生成支付二维码 这边就需要去调用微信的支付二维码接口了 需要的参数是 session_id, timeStamp, nonceStr, package ...

  8. 微信小程序如何开通支付功能?

    微信小程序商城支付方式有哪些,如何开通小程序商城的支付功能,商家开通小程序支付功能的条件有哪些,小程序支付和微商城支付有冲突吗,小程序商城支付方式下商家如何提现,手续费多少? 微信小程序商城支付方式 ...

  9. 微信小程序服务商模式支付巨坑解决!

    今日有个在同一个小程序支付 款项需要付到不同的银行卡里去??? 于是找了下微信小程序支付文档,只有个requestPayment方法 emmm 去看看小程序后台吧 ok 有个微信支付  但是只能绑定一 ...

  10. 微信小程序云开发支付

    微信小程序的云开发支付先看下微信官方给出的流程图: 这张图里,开发者只需要关注的是小程序和云函数端即可:云函数做了很多参数的处理,所以我们不需要关注证书,签名等,只需要调用相应的函数即可:接下来大致说 ...

最新文章

  1. 航天智慧物流创意组-技术培训
  2. System Center 2012 R2 CM系列之安装Configuration Manager
  3. iOS - Quartz 2D 画板绘制
  4. mapreduce编程实例(4)-求中位数和标准差
  5. wsgiserver python 漏洞_简单的WSGI server
  6. 一步一步学习iOS 5编程(第三版)-PDF中文版-正式发布!
  7. android dp sp px_规范|iOS与Android设计规范解析(一)
  8. linux下的C语言开发(gdb调试)
  9. Caused by: org.apache.ibatis.ognl.OgnlException: source is null for getProperty(null, mil_id)
  10. 阿里图标库的基本使用
  11. 转android gralloc流程分析for msm8960
  12. 华为手机什么时候更新鸿蒙系统_华为鸿蒙2.0系统什么时候可以用 华为鸿蒙2.0系统升级方法介绍[多图]...
  13. 2018美国大学计算机科学,美国大学计算机2018最新排名
  14. GooglePlay上架流程
  15. 计算机信息检索技术实质上是逻辑运算,在信息检索的实际过程中,如需要扩大检索范围时,如何调整检索策略...
  16. 贵州:科技创新促高质量发展
  17. java smb删除指定文件,java 利用SMB向远道机器写文件
  18. 掘安杯原题复现---Web签到题
  19. 移动端 简易的table表格
  20. 判断两个向量是否平行

热门文章

  1. 中芯国际公布最新人事调整(5张数据表揭开公司真实情况)
  2. 腾讯社交广告大赛 —— 特征与模型介绍
  3. 若依ruoyi框架整合magic-api快速开发
  4. 友盟推送:测试模式推送完成,但却收不到推送信息
  5. 微机原理笔记day01 计算机发展史,和计算机组成部分
  6. php自动生成word目录,word目录自动生成,word如何自动生成目录
  7. java mis_关于使用java开发Mis系统的相关内容。
  8. iPhone真机测试Crash信息分析
  9. 计算机模拟超光速,超光速十代笔记本电脑怎么样-电脑测评
  10. matlab设置图片背景透明_MATLAB设置图片背景透明,和设定大小,适合论文中使用...