本demo基于微信扫码支付退款(扫码支付暂时没放出demo下次有时间补上)
由于只是demo很多东西没有进行封装
需注意这两个参数我使用的是out_trade_no
请求XML示例
<xml>
<appid>wx2421b1c4370ec43b</appid>
<mch_id>10000100</mch_id>
<nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str>
<out_refund_no>1415701182</out_refund_no>
<out_trade_no>1415757673</out_trade_no>
<refund_fee>1</refund_fee>
<total_fee>1</total_fee>
<transaction_id></transaction_id>
<sign>FE56DD4AA85C0EECA82C35595A69E153</sign>
</xml>
逻辑代码
public static void main(String[] args) {
try {
//构建参数
Map<String, String> dataMap = new HashMap<>();
dataMap.put("appid","wx#################");
dataMap.put("mch_id","137#############");
//自行实现该随机串
dataMap.put("nonce_str",Core.MD5("12344"));
dataMap.put("out_trade_no","P190808170038402889c5318502");
dataMap.put("out_refund_no","P190808170038402889c5318502");
dataMap.put("total_fee","1");
dataMap.put("refund_fee","1");
dataMap.put("refund_desc","退款");
//生成签名
String sign = WXPayUtil.generateSignature(dataMap, "rv4###################");
dataMap.put("sign", sign);
//map数据转xml
String xmlString = XMLBeanUtil.map2XmlString(dataMap);
//发起退款
doRefund("137####", "https://api.mch.weixin.qq.com/secapi/pay/refund", xmlString);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param mchId 商户ID
* @param url 请求URL
* @param data 退款参数
* @return
* @throws Exception
*/
public static String doRefund(String mchId, String url, String data) throws Exception {
/**
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");
//这里自行实现我是使用数据库配置将证书上传到了服务器可以使用 FileInputStream读取本地文件
ByteArrayInputStream inputStream = FileUtil.getInputStream("https://############################.p12");
try {
//这里写密码..默认是你的MCHID
keyStore.load(inputStream, mchId.toCharArray());
} finally {
inputStream.close();
}
SSLContext sslcontext = SSLContexts.custom()
//这里也是写密码的
.loadKeyMaterial(keyStore, mchId.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
HttpPost httpost = new HttpPost(url);
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();
}
}
微信签名工具类
/**
* 生成签名
* @param data 待签名数据
* @param key API密钥
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key) throws Exception {
return generateSignature(data, key, SignType.MD5);
}
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (SignType.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
map转XML工具类
public static String map2XmlString(Map<String, String> map) {
String xmlResult = "";
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
for (String key : map.keySet()) {
String value = "<![CDATA[" + map.get(key) + "]]>";
sb.append("<" + key + ">" + value + "</" + key + ">");
System.out.println();
}
sb.append("</xml>");
xmlResult = sb.toString();
return xmlResult;
}