官方文档
企业付款
直接上代码
关键入参
package cn.country.cunyue.app.pojo.dto.weixin;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "net.mondelez.scan.microservice.entity.vo.WxMchPayB2c", description = "微信商户平台-微信支付-企业付款到零钱")
public class WxMchPayB2c {
@ApiModelProperty(value = "申请商户号的appid或商户号绑定的appid", required = true)
private String mch_appid;
@ApiModelProperty(value = "微信支付分配的商户号", required = true)
private String mchid;
@ApiModelProperty(value = "微信支付分配的终端设备号", required = false)
private String device_info;
@ApiModelProperty(value = "随机字符串,不长于32位", required = true)
private String nonce_str;
@ApiModelProperty(value = "签名,签名算法:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3", required = true)
private String sign;
@ApiModelProperty(value = "商户订单号,需保持唯一性(只能是字母或者数字,不能包含有其它字符)", required = true)
private String partner_trade_no;
@ApiModelProperty(value = "商户appid下,某用户的openid", required = true)
private String openid;
@ApiModelProperty(value = "校验用户姓名选项,NO_CHECK:不校验真实姓名,FORCE_CHECK:强校验真实姓名", required = true)
private String check_name = "NO_CHECK";
@ApiModelProperty(value = "收款用户真实姓名,如果check_name设置为FORCE_CHECK,则必填用户真实姓名,如需电子回单,需要传入收款用户姓名", required = false)
private String re_user_name;
@ApiModelProperty(value = "企业付款金额,单位为分", required = true)
private Integer amount;
@ApiModelProperty(value = "企业付款备注,必填。注意:备注中的敏感词会被转成字符*", required = true)
private String desc;
@ApiModelProperty(value = "Ip地址,该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IP", required = false)
private String spbill_create_ip;
}
帮助方法
package cn.country.cunyue.app.application.utils;
import cn.country.cunyue.app.pojo.dto.weixin.WxMchPayB2c;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.SocketTimeoutException;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@Slf4j
public class WeixinPayUtils {
private static final String TRANS_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
public static String createSign(String signKey, SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.keySet();
for (Object set : es) {
String k = set.toString();
Object v = parameters.get(k);
sb.append(k).append("=").append(v.toString()).append("&");
}
sb.append("key=").append(signKey);
return str2MD5(sb.toString(), "utf-8").toUpperCase();
}
public static String str2MD5(String data, String encode) {
String resultString = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
if (encode == null || "".equals(encode))
resultString = byteArrayToHexString(md.digest(data.getBytes()));
else {
resultString = byteArrayToHexString(md.digest(data.getBytes(encode)));
}
} catch (Exception exception) {
}
return resultString;
}
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String map2XML(SortedMap<Object, Object> dataMap) {
StringBuffer sb = new StringBuffer();
Set<Object> objSet = dataMap.keySet();
sb.append("<xml>\n");
for (Object key : objSet) {
if (key == null) {
continue;
}
Object value = dataMap.get(key);
sb.append("<").append(key.toString()).append(">").append(value).append("</").append(key.toString()).append(">\n");
}
sb.append("</xml>");
return sb.toString();
}
private String createNonceStr(int count) {
String[] nums = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
int maxIndex = nums.length - 1;
int numIndex;
StringBuilder builder = new StringBuilder(count);
for (int i = 0; i < count; i++) {
numIndex = (int) (Math.random() * maxIndex);
builder.append(nums[numIndex]);
}
return builder.toString();
}
public static void main(String[] args) {
String key = "192006250b4c09247ec02edce69f6a2d";
SortedMap<Object, Object> map = new TreeMap<>();
map.put("appid", "wxd930ea5d5a258f4f");
map.put("mch_id", "10000100");
map.put("device_info", "1000");
map.put("body", "test");
map.put("nonce_str", "ibuaiVcKdpRxkhJA");
String sign = WeixinPayUtils.createSign(key, map);
map.put("sign", sign);
String xmlParam = WeixinPayUtils.map2XML(map);
System.out.println(xmlParam);
}
private static KeyStore initCert(String certPath, String mchid) {
KeyStore keyStore = null;
FileInputStream instream = null;
try {
keyStore = KeyStore.getInstance("PKCS12");
instream = new FileInputStream(new File(certPath));
keyStore.load(instream, mchid.toCharArray());
} catch (KeyStoreException e) {
log.error(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.error(e.getMessage(), e);
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage(), e);
} catch (CertificateException e) {
log.error(e.getMessage(), e);
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
if (instream != null) {
try {
instream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
return keyStore;
}
private static CloseableHttpClient createHttpClient(KeyStore keyStore, char[] keyPassword) {
SSLContext sslcontext = null;
try {
sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, keyPassword).build();
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage(), e);
} catch (KeyManagementException e) {
log.error(e.getMessage(), e);
} catch (KeyStoreException e) {
log.error(e.getMessage(), e);
} catch (UnrecoverableKeyException e) {
log.error(e.getMessage(), e);
}
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1"}, null,
new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslSession) {
if ("api.mch.weixin.qq.com".equals(hostname)) {
return true;
} else {
HostnameVerifier hv = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
return hv.verify(hostname, sslSession);
}
}
});
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
return httpClient;
}
public static String post(String url, String xmlObj, String mchid, String certPath) {
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(10000).build();
KeyStore keyStore = initCert(certPath, mchid);
CloseableHttpClient httpClient = createHttpClient(keyStore, mchid.toCharArray());
String result = null;
HttpPost httpPost = new HttpPost(url);
String defaultCharset = "UTF-8";
StringEntity postEntity = new StringEntity(xmlObj, defaultCharset);
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
httpPost.setConfig(requestConfig);
try {
HttpResponse res = httpClient.execute(httpPost);
if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = res.getEntity();
result = EntityUtils.toString(entity, defaultCharset);
}
} catch (ConnectionPoolTimeoutException e) {
log.error(e.getMessage(), e);
} catch (ConnectTimeoutException e) {
log.error(e.getMessage(), e);
} catch (SocketTimeoutException e) {
log.error(e.getMessage(), e);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
httpPost.abort();
}
return result;
}
public static String doTransfers(String key, String certPath, WxMchPayB2c model) throws IllegalAccessException {
SortedMap<Object, Object> map = new TreeMap<>();
Field[] declaredFields = model.getClass().getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
String k = field.getName();
Object v = field.get(model);
if (v != null) {
map.put(k, v);
}
}
String sign = WeixinPayUtils.createSign(key, map);
map.put("sign", sign);
String xmlParam = WeixinPayUtils.map2XML(map);
String result = post(TRANS_URL, xmlParam, model.getMchid(), certPath);
return result;
}
}