微信小程序使用建行支付

微信小程序使用建行支付

一、交易流程说明

正在上传…重新上传取消

二、接口说明

字段说明类型必传
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交易码,由建行统一分配 ,为530590CHAR(6)
MACMAC校验域,采用标准MD5算法,由商户实现CHAR(32)
TYPE接口类型,分行业务人员在P2员工渠道后台设置防钓鱼的开关。1-防钓鱼接口CHAR(1)
PUB公钥后30位,商户从建行商户服务平台下载,截取后30位。仅作为源串参加MD5摘要,不作为参数传递CHAR(30)
GATEWAY网关类型,默认为0VARCHAR(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,当前调起支付的小程序/公众号APPIDCHAR(32)
SUB_OPENID用户子标识用户在小程序/公众号appid下的唯一标识,小程序通过wx.login获取,接口文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html?t=20161122CHAR(128)
WX_CHANNELID渠道商号,对于商户自定义的渠道商号当该字段有值时参与MAC校验,否则不参与MAC校验。CHAR(20)
RETURN_FIELD返回信息位图,共20位,商户通知是否返回某个字段的位图,0或空-不返回,1-返回。第1位:是否返回OPENID和SUB_OPENID第2位:保留位,默认送0第3位:保留位,默认送0 第4位:是否返回支付详细信息字段示例:10000000000000000000CHAR(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";


    @Autowired
    private JHPayProperties jhPayProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public 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方式访问网银获取PAYURL
        ResponseEntity<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;
    }

    @Override
    public 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);
    }
}

你可能感兴趣的

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值