微信的业务文档一向看了都想让人恶心,所以我自己排完坑就总结出来 这个微信提现的功能,大家放心使用,经过企业实践的,有问题可以留言沟通
package com.ydwl.shantui.user.util;
import com.ydwl.shantui.util.SignUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.*;
/**
* 微信工具类
*
* @author weiyimin
* @create 2022-02-28 09:42
**/
@Slf4j
@Data
public class WxPayUtil {
public static final String WITHDRAW_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
private static final String CERTIFICATE = "/data/project/certificate/apiclient_cert.p12";
public static String appId;
public static String mchId;
public static String wxSingKey;
/**
* 微信提现(企业付款)
*
* @param orderNo 自己生成的订单号
* @param openId 微信提供的openId
* @param amount 提现金额
* @param ip 默认传null
* @param desc 备注
* @return
*/
public static Map payForUser(String orderNo, String openId, Long amount, String ip, String desc) {
Map map;
SortedMap<String, Object> params = new TreeMap<>();
params.put("mch_appid", appId);
params.put("mchid", mchId);
params.put("partner_trade_no", orderNo);
params.put("nonce_str", getRandomStr(32).toUpperCase());
params.put("openid", openId);
params.put("check_name", WxPayConstant.CHECK_NAME);
params.put("amount", amount.toString());
params.put("desc", desc);
String sign = SignUtil.getSign(params, wxSingKey);
params.put("sign", sign);
String xmlInfo = getRequestXml(params);
try {
CloseableHttpResponse response = wxPost(WITHDRAW_URL, xmlInfo, true);
String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
map = doXmlParse(transfersXml);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return map;
}
/**
* 查询微信提现是否成功(企业付款)
*/
public static Map checkPay(String orderNo) {
Map map;
SortedMap<String, Object> params = new TreeMap<>();
params.put("appid", appId);
params.put("mch_id", mchId);
params.put("partner_trade_no", orderNo);
params.put("nonce_str", getRandomStr(32).toUpperCase());
String sign = SignUtil.getSign(params, wxSingKey);
params.put("sign", sign);
String xmlInfo = getRequestXml(params);
try {
CloseableHttpResponse response = wxPost(WxPayConstant.CHECK_SUCCESS_URL, xmlInfo, true);
String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
map = doXmlParse(transfersXml);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return map;
}
/**
* 生成随机数
*
* @param length 生成字符串的长度
* @return
*/
public static String getRandomStr(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* 请求xml组装
*
* @return
*/
private static String getRequestXml(SortedMap<String, Object> parameters) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
Set es = parameters.entrySet();
for (Object e : es) {
Map.Entry entry = (Map.Entry) e;
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
sb.append("<").append(key).append(">").append("<![CDATA[").append(value).append("]]></").append(key).append(">");
} else {
sb.append("<").append(key).append(">").append(value).append("</").append(key).append(">");
}
}
sb.append("</xml>");
return sb.toString();
}
/**
* xml解析
*
* @return
*/
private static Map doXmlParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=".*"", "encoding="UTF-8"");
if ("".equals(strxml)) {
return null;
}
Map m = new HashMap(16);
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
for (Object aList : list) {
Element e = (Element) aList;
String k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
private static String getChildrenText(List children) {
StringBuilder sb = new StringBuilder();
if (!children.isEmpty()) {
for (Object aChildren : children) {
Element e = (Element) aChildren;
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<").append(name).append(">");
if (!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</").append(name).append(">");
}
}
return sb.toString();
}
/**
* 发送post请求
*
* @param url 请求地址
* @param outputEntity 发送内容
* @param isLoadCert 是否加载证书
*/
public static CloseableHttpResponse wxPost(String url, String outputEntity, boolean isLoadCert) throws Exception {
HttpPost httpPost = new HttpPost(url);
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(new StringEntity(outputEntity, "UTF-8"));
if (isLoadCert) {
SSLConnectionSocketFactory sslConnectionSocketFactory = initCert();
// 加载含有证书的http请求
return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build().execute(httpPost);
} else {
return HttpClients.custom().build().execute(httpPost);
}
}
/**
* 加载证书
*/
public static SSLConnectionSocketFactory initCert() throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream inputStream = new FileInputStream(CERTIFICATE);
if (null == inputStream) {
return null;
}
// InputStream inputStream = WxPayUtil.class.getClassLoader().getResourceAsStream("static/apiclient_cert.p12");
keyStore.load(inputStream, WxPayConstant.MCH_ID.toCharArray());
if (null != inputStream) {
inputStream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WxPayConstant.MCH_ID.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, new DefaultHostnameVerifier());
return sslsf;
}
}