WxService.java:
package com.lws.test.core.wechat;
import com.ygxk.social.core.utils.MD5Util;
import com.ygxk.social.core.utils.StringUtil;
import com.ygxk.social.core.wechat.WxKeyConstant;
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.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.springframework.util.ResourceUtils;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.*;
/**
* @Description 微信 工具类
* @Author Li Wei Shan
* @Date 2020-12-09 18:25
* @Version 1.0
**/
@Slf4j
public class WxService {
/**
* 微信提现(企业付款)
*/
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", WxKeyConstant.APP_ID);
params.put("mchid", WxKeyConstant.MCH_ID);
params.put("partner_trade_no", orderNo);
params.put("nonce_str", StringUtil.getRandomString(32));
params.put("openid", openId);
params.put("check_name", WxKeyConstant.CHECK_NAME);
params.put("amount", amount.toString());
params.put("spbill_create_ip", ip);
params.put("desc", desc);
String sign = createSign(params);
params.put("sign", sign);
String xmlInfo = getRequestXml(params);
log.debug("WxService==payForUser==xmlInfo==" + xmlInfo);
try {
CloseableHttpResponse response = WxPost(WxKeyConstant.WITHDRAW_URL, xmlInfo, true);
String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
log.debug("transfersXml---"+transfersXml);
map = doXMLParse(transfersXml);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return map;
}
/**
* 生成签名
* @return
*/
private static String createSign(SortedMap<String, Object> parameters) {
StringBuilder sb = new StringBuilder();
Set es = parameters.entrySet();
for (Object e : es) {
Map.Entry entry = (Map.Entry) e;
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k).append("=").append(v).append("&");
}
}
sb.append("key=").append(WxKeyConstant.WX_SING_KEY);
log.debug("签名结果==" + sb.toString());
return MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
}
/**
* 请求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();
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) {
// 加载含有证书的http请求
return HttpClients.custom().setSSLSocketFactory(initCert()).build().execute(httpPost);
} else {
return HttpClients.custom().build().execute(httpPost);
}
}
/**
* 加载证书
*/
public static SSLConnectionSocketFactory initCert() throws Exception {
FileInputStream instream = null;
KeyStore keyStore = KeyStore.getInstance("PKCS12");
File file = ResourceUtils.getFile(WxKeyConstant.CERT_PATH);
instream = new FileInputStream(file);
keyStore.load(instream, WxKeyConstant.MCH_ID.toCharArray());
if (null != instream) {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WxKeyConstant.MCH_ID.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, new DefaultHostnameVerifier());
return sslsf;
}
}
WxKeyConstant.java:
package com.lws.test.core.wechat;
/**
* @Description 微信使用的Key的常量定义
* @Author Li Wei Shan
* @Date 2020-12-09 18:26
* @Version 1.0
**/
public class WxKeyConstant {
/**
* appid
*/
public static final String APP_ID = "xxx";
/**
* appSercet
*/
public static final String APP_SECRET = "xxx";
/**
* 商户号
*/
public static final String MCH_ID = "xxx";
/**
* 支付秘钥
*/
public static final String WX_SING_KEY = "xxx";
/**
* 证书路径
*/
public static final String CERT_PATH = "/apiclient_cert.p12";
/**
* 回调地址
*/
public static final String NOTIFY_URL = "";
/**
* 是否校验用户姓名 NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
*/
public static final String CHECK_NAME = "NO_CHECK";
/**
* 付款url
*/
public static final String WITHDRAW_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
}