微信企业付款到银行卡(微信转账)(Java完整版)

业务介绍

微信付款到银行卡,也就是转账。需要将银行卡号、卡主真实姓名按照微信支付制定的加密规则进行加密,(开发完感觉加密比转账复杂,哈哈哈)。加密的秘钥,也就是钥匙,也要通过请求向微信获取,重点是获取到之后,并不能直接使用。还要进行两次处理。(太难了)。最后用处理好的秘钥,对银行卡号、姓名进行加密。发送转账请求就完成了。

前置工作

证书(apiclient_cert.p12)、商户号(mch_id)、secret。

工具类

加密用到的工具类(常量PKCS8_PUBLIC需要改成自己的,后面会讲)

public class RSAUtils {

    /**
     * rsa加密公钥
     * 请求微信api获得pkcs1格式
     * 通过转换工具转换成pkcs8格式
     */
    private static final String PKCS8_PUBLIC ="";


    public static byte[] decrypt(byte[] encryptedBytes, PrivateKey privateKey, int keyLength, int reserveSize, String cipherAlgorithm) throws Exception {
        int keyByteSize = keyLength / 8;
        int decryptBlockSize = keyByteSize - reserveSize;
        int nBlock = encryptedBytes.length / keyByteSize;
        ByteArrayOutputStream outbuf = null;
        try {
            Cipher cipher = Cipher.getInstance(cipherAlgorithm);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize);
            for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) {
                int inputLen = encryptedBytes.length - offset;
                if (inputLen > keyByteSize) {
                    inputLen = keyByteSize;
                }
                byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen);
                outbuf.write(decryptedBlock);
            }
            outbuf.flush();
            return outbuf.toByteArray();
        } catch (Exception e) {
            throw new Exception("DEENCRYPT ERROR:", e);
        } finally {
            try{
                if(outbuf != null){
                    outbuf.close();
                }
            }catch (Exception e){
                outbuf = null;
                throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);
            }
        }
    }
    public static byte[] encrypt(byte[] plainBytes, PublicKey publicKey, int keyLength, int reserveSize, String cipherAlgorithm) throws Exception {
        int keyByteSize = keyLength / 8;
        int encryptBlockSize = keyByteSize - reserveSize;
        int nBlock = plainBytes.length / encryptBlockSize;
        if ((plainBytes.length % encryptBlockSize) != 0) {
            nBlock += 1;
        }
        ByteArrayOutputStream outbuf = null;
        try {
            Cipher cipher = Cipher.getInstance(cipherAlgorithm);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            outbuf = new ByteArrayOutputStream(nBlock * keyByteSize);
            for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) {
                int inputLen = plainBytes.length - offset;
                if (inputLen > encryptBlockSize) {
                    inputLen = encryptBlockSize;
                }
                byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen);
                outbuf.write(encryptedBlock);
            }
            outbuf.flush();
            return outbuf.toByteArray();
        } catch (Exception e) {
            throw new Exception("ENCRYPT ERROR:", e);
        } finally {
            try{
                if(outbuf != null){
                    outbuf.close();
                }
            }catch (Exception e){
                outbuf = null;
                throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);
            }
        }
    }
    public static PrivateKey getPriKey(String privateKeyPath,String keyAlgorithm){
        PrivateKey privateKey = null;
        InputStream inputStream = null;
        try {
            if(inputStream==null){
                System.out.println("hahhah1!");
            }

            inputStream = new FileInputStream(privateKeyPath);
            System.out.println("hahhah2!");
            privateKey = getPrivateKey(inputStream,keyAlgorithm);
            System.out.println("hahhah3!");
        } catch (Exception e) {
            System.out.println("加载私钥出错!");
        } finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                }catch (Exception e){
                    System.out.println("加载私钥,关闭流时出错!");
                }
            }
        }
        return privateKey;
    }
    /*public static PublicKey getPubKey(String publicKeyPath,String keyAlgorithm){
        PublicKey publicKey = null;
        InputStream inputStream = null;
        try
        {
            System.out.println("getPubkey 1......");

            inputStream = new FileInputStream(publicKeyPath);
            System.out.println("getPubkey 2......");

            publicKey = getPublicKey(inputStream,keyAlgorithm);
            System.out.println("getPubkey 3......");

        } catch (Exception e) {

            e.printStackTrace();//EAD PUBLIC KEY ERROR
            System.out.println("加载公钥出错!");
        } finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                }catch (Exception e){
                    System.out.println("加载公钥,关闭流时出错!");
                }
            }
        }
        return publicKey;
    }  */
    public static PublicKey getPublicKey(String keyAlgorithm) throws Exception {
        try
        {
            /*System.out.println("b1.........");
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            System.out.println("b2.........");
            StringBuilder sb = new StringBuilder();
            String readLine = null;
            System.out.println("b3.........");
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            System.out.println("b4.........");*/
            //加载公钥
            X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(decodeBase64(PKCS8_PUBLIC));
            /*//读取公钥
            X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(decodeBase64(sb.toString())); */
            System.out.println("b5.........");
            KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
            System.out.println("b6.........");
            //下行出错  java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=127, too big.
            PublicKey publicKey = keyFactory.generatePublic(pubX509);
            System.out.println("b7.........");
            return publicKey;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("b8.........");
            throw new Exception("READ PUBLIC KEY ERROR:", e);
        } /*finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                inputStream = null;
                throw new Exception("INPUT STREAM CLOSE ERROR:", e);
            }
        }  */
    }
    public static PrivateKey getPrivateKey(InputStream inputStream, String keyAlgorithm) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder sb = new StringBuilder();
            String readLine = null;
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            System.out.println("hahhah4!"+decodeBase64(sb.toString()));
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decodeBase64(sb.toString()));
            System.out.println("hahhah5!");
            KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
            System.out.println("hahhah6!");
            PrivateKey privateKey = keyFactory.generatePrivate(priPKCS8);
            System.out.println("hahhah7!");
            return privateKey;
        } catch (Exception e) {
            throw new Exception("READ PRIVATE KEY ERROR:" ,e);
        }  finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                inputStream = null;
                throw new Exception("INPUT STREAM CLOSE ERROR:", e);
            }
        }
    }
    //一下面是base64的编码和解码
    public static String encodeBase64(byte[]input) throws Exception{
        Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
        Method mainMethod= clazz.getMethod("encode", byte[].class);
        mainMethod.setAccessible(true);
        Object retObj=mainMethod.invoke(null, new Object[]{input});
        return (String)retObj;
    }
    /***
     * decode by Base64
     */
    public static byte[] decodeBase64(String input) throws Exception{
        Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
        Method mainMethod= clazz.getMethod("decode", String.class);
        mainMethod.setAccessible(true);
        Object retObj=mainMethod.invoke(null, input);
        return (byte[])retObj;
    }


}

MD5工具类

public final class Md5Util {
	private static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
	private static Md5Util instance = null;
	private Md5Util() { 		
	}
	public synchronized static Md5Util getInstance() {
		if(instance==null){
			instance=new Md5Util();
		}
		return instance;
	}
	public String getShortToken(String arg0) {
		return encoder(arg0).substring(8,24);
	}
	public String getLongToken(String arg0) {
		return encoder(arg0).toString();
	}
	private StringBuffer encoder(String arg){
		if(arg==null){
			arg="";
		}
		MessageDigest md5 = null;
		try {
			md5=MessageDigest.getInstance("MD5");
			md5.update(arg.getBytes("UTF8"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return toHex(md5.digest());
	}
	private StringBuffer toHex(byte[] bytes) {
		StringBuffer str = new StringBuffer(32);
		int length=bytes.length;
		for (int i = 0; i < length; i++) {
			str.append(hexDigits[(bytes[i] & 0xf0) >> 4]);
			str.append(hexDigits[bytes[i] & 0x0f]);
		}
		bytes=null;
		return str;
	}
	public static void main(String a[]){

		Md5Util instance = Md5Util.getInstance();
		String longToken = instance.getLongToken("123456");
		System.out.println(longToken);

	}
}

向微信发送请求用到的工具类

public class PayUtil {
 
    /**
     * <p>
     * 携带证书post请求
     * </p>
     *
     * @param mchId
	 * @param url
	 * @param data
	 * @param certPath
     * @return java.lang.String
     * @author Winder
     * @date 2021/1/25 下午2:51
     */
    public static String doPublicKey(String mchId, String url, String data,String certPath) throws Exception {
        /**
         * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
         */
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //P12文件目录 证书路径,这里需要你自己修改,linux下还是windows下的根路径
        FileInputStream instream = new FileInputStream(certPath);
        try {
            keyStore.load(instream, mchId.toCharArray());//这里写密码..默认是你的MCHID
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, mchId.toCharArray())//这里也是写密码的
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        try {
            HttpPost httpost = new HttpPost(url); //有些api会因为设置请求头无法正常响应
//            httpost.addHeader("Connection", "keep-alive");
//            httpost.addHeader("Accept", "*/*");
//            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//            httpost.addHeader("Host", "api.mch.weixin.qq.com");
//            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
//            httpost.addHeader("Cache-Control", "max-age=0");
//            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();

                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

Java Bean

/**
 * <p>
 * 获取RSA公钥bean
 * </p>
 *
 * @author Winder
 * @since 2021/1/25 上午11:33
 */
public class RSAPublicKeyBean implements Serializable {
    private static final long serialVersionUID = 1L;

    /**商户号*/
    private String mch_id;
    /**随机字符串*/
    private String nonce_str;
    /**签名*/
    private String sign;
    /**签名类型*/
    private String sign_type;

    public String getMch_id() {
        return mch_id;
    }

    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }

    public String getNonce_str() {
        return nonce_str;
    }

    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getSign_type() {
        return sign_type;
    }

    public void setSign_type(String sign_type) {
        this.sign_type = sign_type;
    }
}

/**
 * <p>
 * 企业付款到银行卡bean
 * </p>
 *
 * @author Winder
 * @since 2021/1/25 上午10:13
 */
public class TransferBank implements Serializable {
    private static final long serialVersionUID = 1L;
    /**商户号*/
    private String mch_id;
    /**商户订单号*/
    private String partner_trade_no;
    /**随机字符串*/
    private String nonce_str;
    /**签名*/
    private String sign;
    /**收款方银行卡号*/
    private String enc_bank_no;
    /**收款方用户名*/
    private String enc_true_name;
    /**收款方开户行代号 https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_4*/
    private String bank_code;
    /**付款金额 单位分*/
    private int amount;
    /**付款说明,即备注(非必填)*/
    private String desc;

    public String getMch_id() {
        return mch_id;
    }

    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }

    public String getPartner_trade_no() {
        return partner_trade_no;
    }

    public void setPartner_trade_no(String partner_trade_no) {
        this.partner_trade_no = partner_trade_no;
    }

    public String getNonce_str() {
        return nonce_str;
    }

    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getEnc_bank_no() {
        return enc_bank_no;
    }

    public void setEnc_bank_no(String enc_bank_no) {
        this.enc_bank_no = enc_bank_no;
    }

    public String getEnc_true_name() {
        return enc_true_name;
    }

    public void setEnc_true_name(String enc_true_name) {
        this.enc_true_name = enc_true_name;
    }

    public String getBank_code() {
        return bank_code;
    }

    public void setBank_code(String bank_code) {
        this.bank_code = bank_code;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

配置类(放在resources目录下)

文件名为wxpay.properties(该文件主要的作用是方便管理这些变量,非必须)

#转账到银行卡接口
TRANSFERSBANKURL=https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank
#获取微信共钥接口
GETPUBLICKEY=https://fraud.mch.weixin.qq.com/risk/getpublickey
##商户号
MCHId=这个当然不能展示了
##secret
APIKEY=哈哈
#商户号支付证书
certs.path=证书的存放目录 eg:/home/app/../apiclient_cert.p12

到这里该准备的工具类、JavaBean、配置文件都准备好了。接下来开始进入业务逻辑。
首先我们向微信发送请求,获取PKCS#1 格式密钥:

    /**
     * <p>
     * 生成获取rsa公钥的签名
     * </p>
     *
     * @param bean
     * @return java.lang.String
     * @author Winder
     * @date 2021/1/25 下午3:41
     */
    public static String createGetPublicKeySign(RSAPublicKeyBean bean){
        StringBuffer sign = new StringBuffer();
        sign.append("mch_id=").append(bean.getMch_id());
        sign.append("&nonce_str=").append(bean.getNonce_str());
        sign.append("&sign_type=").append(bean.getSign_type());
        sign.append("&key=").append(PropertyTool.getValue("/wxpay.properties", "APIKEY"));
        System.out.println("获取公钥签名参数:" + sign.toString());
        String signStr = Md5Util.getInstance().getLongToken(sign.toString()).toUpperCase();
        System.out.println("获取公钥签名:" + signStr);
        return signStr;
    }
    /**
     * <p>
     * 获取rsa公钥
     * </p>
     *
     * @param
     * @return java.util.Map
     * @author Winder
     * @date 2021/1/26 上午9:17
     */
    public static Map getPublicKey() throws Exception {
        //封装请求参数
        RSAPublicKeyBean bean = new RSAPublicKeyBean();
        String str = UUIDUtil.getUUID();
        bean.setMch_id(PropertyTool.getValue("/wxpay.properties", "MCHId"));
        bean.setNonce_str(str);
        bean.setSign_type("MD5");
        String sign = createGetPublicKeySign(bean);
        bean.setSign(sign);
        XMLUtil xmlUtil = new XMLUtil();
        xmlUtil.xstream().alias("xml", bean.getClass());
        String xml = xmlUtil.xstream().toXML(bean);
        System.out.println("请求xml:" + xml);
        String mchId = PropertyTool.getValue("/wxpay.properties", "MCHId");
        String certFilePath = PropertyTool.getValue("/wxpay.properties", "certs.path.linux");;//证书目录位置
        //发送请求
        String response = PayUtil.doPublicKey(mchId, PropertyTool.getValue("/wxpay.properties", "GETPUBLICKEY"), xml, certFilePath);
        System.out.println(response);
        Map<String, String> map = xmlUtil.parseXml(response);
        return map;
    }

成功的话在输出中可以看到以下内容:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEArT82k67xybiJS9AD8nNAeuDYdrtCRaxkS6cgs8L9h83eqlDTlrdw
zBVSv5V4imTq/URbXn4K0V/KJ1TwDrqOI8hamGB0fvU13WW1NcJuv41RnJVua0QA
lS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+2kUWG94FccArNnBtBqqvFncXgQsm98JB
3a62NbS1ePP/hMI7Kkz+JNMyYsWkrOUFDCXAbSZkWBJekY4nGZtK1erqGRve8Jbx
TWirAm/s08rUrjOuZFA21/EI2nea3DidJMTVnXVPY2qcAjF+595shwUKyTjKB8v1
REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfqjwIDAQAB
-----END RSA PUBLIC KEY-----
到这里就拿到微信提供的公钥了,为PKCS#1 格式密钥,但是Java的同学是不能直接使用的,还需要转换。转换成PKCS#8 格式密钥。

到这儿已经完成一半了,大家可以休息一会了,放松一下。

这是微信官方提供的转换方式
PKCS#1 转 PKCS#8:
openssl rsa -RSAPublicKey_in -in -pubout
PKCS#8 转 PKCS#1:
openssl rsa -pubin -in -RSAPublicKey_out

我是在这儿转换的:
https://www.ssleye.com/web/pkcs

转换后的秘钥
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArT82k67xybiJS9AD8nNA
euDYdrtCRaxkS6cgs8L9h83eqlDTlrdwzBVSv5V4imTq/URbXn4K0V/KJ1TwDrqO
I8hamGB0fvU13WW1NcJuv41RnJVua0QAlS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+
lkUWG94FccArNnBtBqqvFncXgQsm98JB3a42NbS1ePP/hMI7Kkz+JNMyYsWkrOUF
DCXAbSZkWBJekY4nGZtK1erqGRve8JbxTWirAm/s08rUrjOuZFA21/EI2nea3Did
JMTVnXVPY2qcAjF+595shwUKyTjKB8v1REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfq
jwIDAQAB
-----END PUBLIC KEY-----
大家还记得第一个工具类里的常量吗?。。。。。。没错那儿填的就是这个(去除-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----)。

 /**
     * <p>
     * 按照微信要求进行加密
     * </p>
     *
     * @param data 加密前的开户姓名/银行卡号
     * @return java.lang.String 加密后秘文
     * @author Winder
     * @date 2021/1/26 上午10:28
     */
    public static String encrypt(String data){
        PublicKey pub = null;
        try {
            //rsa加密
            pub = RSAUtils.getPublicKey("RSA");
            String rsa = "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING";
            byte[] estrName = RSAUtils.encrypt(data.getBytes(), pub, 2048, 11, rsa);
            //base64加密
            data = Base64Utils.encodeToString(estrName);
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 /**
     * <p>
     * 生成企业付款到银行卡的签名
     * </p>
     *
     * @param bean
     * @return java.lang.String
     * @author Winder
     * @date 2021/1/25 上午10:43
     */
    public static String createTransferBankSign(TransferBank bean){
        StringBuffer sign = new StringBuffer();
        sign.append("amount=").append(bean.getAmount());
        sign.append("&bank_code=").append(bean.getBank_code());
        if(StringUtils.isNotBlank(bean.getDesc())){
            sign.append("&desc=").append(bean.getDesc());//非必填
        }
        sign.append("&enc_bank_no=").append(bean.getEnc_bank_no());
        sign.append("&enc_true_name=").append(bean.getEnc_true_name());
        sign.append("&mch_id=").append(bean.getMch_id());
        sign.append("&nonce_str=").append(bean.getNonce_str());
        sign.append("&partner_trade_no=").append(bean.getPartner_trade_no());
        sign.append("&key=").append(PropertyTool.getValue("/wxpay.properties", "APIKEY"));
        System.out.println("付款到银行卡签名参数:" + sign.toString());
        String signStr = Md5Util.getInstance().getLongToken(sign.toString()).toUpperCase();
        System.out.println("付款到银行卡签名:" + signStr);
        return signStr;
    }
 /**
     * <p>
     * 转账
     * </p>
     *
     * @param
     * @return void
     * @author Winder
     * @date 2021/1/28 下午5:53
     */
    public static void transferBank() throws Exception {
        TransferBank transferBank = new TransferBank();
        String name = encrypt("姓名");/**修改*/
        String bank = encrypt("银行卡");/**修改*/
        String str = UUIDUtil.getUUID();
        String oderId = UUIDUtil.getUUID();
        transferBank.setAmount(1);/**修改*/
        transferBank.setBank_code("银行代码");/**修改*/
        transferBank.setEnc_bank_no(bank);
        transferBank.setEnc_true_name(name);
        transferBank.setMch_id(PropertyTool.getValue("/wxpay.properties", "MCHId"));
        transferBank.setNonce_str(str);
        transferBank.setPartner_trade_no(oderId);
        transferBank.setDesc("测试转账,每次转一分钱");
        String sign = createTransferBankSign(transferBank);
        transferBank.setSign(sign);
        XMLUtil xmlUtil = new XMLUtil();
        xmlUtil.xstream().alias("xml", transferBank.getClass());
        String xml = xmlUtil.xstream().toXML(transferBank);
        System.out.println("请求xml:" + xml);
        String mchId = PropertyTool.getValue("/wxpay.properties", "MCHId");
        String certFilePath = PropertyTool.getValue("/wxpay.properties", "certs.path.linux");
        String response = PayUtil.doPublicKey(mchId, PropertyTool.getValue("/wxpay.properties", "TRANSFERSBANKURL"), xml, certFilePath);
        System.out.println(response);
    }

总结

到这儿转账工具类就全部结束了,具体业务逻辑还要自己控制,就不多做赘述了。很荣幸为大家分享。最后祝大家都能开发用户喜欢的好的产品、拿到好的薪资。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值