微信企业付款至银行卡 详细Demo 独立封装
大家好,我是梦辛工作室的灵,在最近的开发项目中,需要用到微信的企业付款至银行卡,在有过之前的企业付款到零钱包的封装好,就变的简单了许多,不过我还是在采用RSA加密银行卡 和 真实姓名的步骤上卡了许久,经过我不断地尝试还是搞定了这个功能,为了以后方便使用 顺便封装了下,WxPayUtilV1.0.2版,下面是如何使用:
/**
* 企业付款到银行卡示例
*/
public static void compayWxPayBank() {
try {
// 获取公钥
String key = getWxPayPublicKey();
CompanyWxPayBankBuilder wxPayBankBuilder = new CompanyWxPayBankBuilder("证书路径", key); // key 为微信返回的公钥
wxPayBankBuilder.setMch_id("商户号");
wxPayBankBuilder.setAPI_KEY("APIKEY");
wxPayBankBuilder.setAmount(200); // 支付金额
wxPayBankBuilder.setDesc("支付描述");
wxPayBankBuilder.setEnc_bank_no("银行卡卡号");
wxPayBankBuilder.setEnc_true_name("真实姓名");
wxPayBankBuilder.setBank_code("银行编码");
wxPayBankBuilder.build();// 验证数据
System.out.println(wxPayBankBuilder.hand());// 发送处理
} catch (LackParamExceptions e) {
e.printStackTrace();
}
}
/**
* 获取公钥
*/
public static String getWxPayPublicKey() {
try {
GetPublicKeyBuilder builder = new GetPublicKeyBuilder("证书路径");
builder.setAPI_KEY("APIKEY");
builder.setmch_id("微信商户号");
builder.build();// 验证数据
JSONObject result = builder.hand();
System.out.println(result);// 发送处理
return result.getString("pub_key");
} catch (LackParamExceptions e) {
e.printStackTrace();
}
return null;
}
/**
* 企业付款到银行卡查询示例
*/
public static void compayWxPayBankQuery() {
try {
CompanyWxPayBankQueryBuilder wxPayBankQueryBuilder = new CompanyWxPayBankQueryBuilder("支付证书路径",
"交易订单号(商家,不是微信的)");
wxPayBankQueryBuilder.setMch_id("商户号");
wxPayBankQueryBuilder.setAPI_KEY("APIKEY");
wxPayBankQueryBuilder.build();// 验证数据
System.out.println(wxPayBankQueryBuilder.hand());// 发送处理
} catch (LackParamExceptions e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
有了这个我集成好的工具后,是不是就简单了很多,没有其余更多的复杂逻辑,hand()后就可以拿到对应的处理数据,该工具项目 我还集成了 微信JSAPI付款 发送模板消息 微信退款 微信退款查询 微信企业付款至零钱包 付款至银行卡 等功能,
下面讲一下我企业付款至银行卡步骤(不感兴趣的同学可直接到底部,github去下载源代码):
在拿到商户号秘钥和支付证书的基础上,需先获取到公钥
将以上信息按照ASCII码顺序拼接成以下格式:
mch_id=&nonce_str=&key=
1
然后MD5拿到sign,最后拼接成xml格式:
最后带证书访问值地址:https://fraud.mch.weixin.qq.com/risk/getpublickey
带证书访问代码如下:
public static String httpClientResultGetPublicKey(String url, String xml, String mch_id, String path)
throws Exception {
StringBuffer reultBuffer = new StringBuffer();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(path));
try {
keyStore.load(instream, mch_id.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
HttpPost httpPost = new HttpPost(url);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
StringEntity myEntity = new org.apache.http.entity.StringEntity(xml);
myEntity.setContentType("text/xml;charset=UTF-8");
myEntity.setContentEncoding("utf-8");
httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");
httpPost.setEntity(myEntity);
CloseableHttpResponse response = null;
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (entity != null) {
inputStream = entity.getContent();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
reultBuffer.append(str);
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
httpclient.close();
response.close();
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
}
return reultBuffer.toString();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
访问成功后可以拿到公钥,格式如下:
需要注意的是,这里获取到的秘钥格式是PKCS#1, 我们在用JAVA代码进行RSA加密的时候回报错,这是因为需要将格式转换为PKCS#8才可以,等下后面会讲到
进行企业付款至银行卡
在我们拿到公钥后,就按照以下参数请求,请求格式和加密方法和上面的一样,所需参数为:
这里需要对 银行卡 和真实姓名进行RSA加密,JAVA需要采用 " RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING" 填充方式,(需要将公钥格式转换为PKCS#8),加密代码如下(注意,这里的公钥需将头和尾去掉,即不要 “-----BEGIN RSA PUBLIC KEY-----” 和 “-----END RSA PUBLIC KEY-----”),需要为UTF-8格式:
try {
enc_bank_no_pwd = RSAEncryp.encrypt(enc_bank_no.getBytes("utf-8"), pub_key, 11,
"RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
} catch (Exception e) {
e.printStackTrace();
enc_bank_no_pwd = "";
}
try {
enc_true_name_pwd = RSAEncryp.encrypt(enc_true_name.getBytes("utf-8"), pub_key, 11,
"RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
} catch (Exception e) {
e.printStackTrace();
enc_true_name_pwd = "";
}
public static String encrypt(byte[] plainBytes, String pub_Key, int reserveSize, String cipherAlgorithm)
throws Exception {
PublicKey publicKey = getPublicKey(pub_Key, "RSA");
byte[] estr = encrypt(plainBytes, publicKey, pub_Key.length(), reserveSize, cipherAlgorithm);
return new String(Base64.getEncoder().encode(estr));
}
public static PublicKey getPublicKey(String key, String keyAlgorithm) throws Exception {
try {
//在这里做的秘钥格式转换
org.bouncycastle.asn1.pkcs.RSAPublicKey rsaPublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey
.getInstance(org.bouncycastle.util.encoders.Base64.decode(key));
java.security.spec.RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(
rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent());
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
return publicKey;
} catch (Exception e) {
throw new Exception("READ PUBLIC KEY ERROR:", e);
} finally {
}
}
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);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
然后将这些参数按照ASCII码顺序排序凭借为以下字符串:
amount=&bank_code=&desc=&enc_bank_no=&enc_true_name=&mch_id=&nonce_str=&partner_trade_no=&key=
1
然后MD5拿到sign
然后拼接为以下格式:
然后带证书post到接口地址:https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank
然后就可以啦,企业付款到银行卡查询比较简单,且没有什么需要注意的,我就不说啦,格式和 获取公钥一样,仅是参数不同而已
github入口,记得打个start https://github.com/wintton/MxWxPayUtil