前期准备工作
1.之前微信APP支付的博客
- 1.1 前期获取的参数
- 1.2 配置及参数
https://blog.csdn.net/liang1184750950/article/details/100556420
2.退款证书
- 2.1 微信退款需要使用双向证书,具体获取方式可登录微信商户平台-API安全进行获取
- 2.2 获取的证书样式
- 2.3 .p12证书放在项目resource目录下面进行证书的读取
实战
1. 请求参数及返回值
- 1.1 请求参数
@Data
@AllArgsConstructor
public class WeChatRefundCommand {
@NotNull
private String outTradeNo;//商户订单号
@NotNull
private Integer totalFee;
@NotNull
private Integer refundFee;
}
- 1.2 返回值
@Setter
@Getter
@AllArgsConstructor
@Builder
public class WeChatRefundResponse {
private String result; // 不参与签名,成功标志
}
代码
public WeChatRefundResponse refund(WeChatRefundCommand command) throws Exception {
//请求参数转xml格式
String xml = generateRefundParams(command);
//证书加载,调用退款接口
String returnXml = CertHttpUtil.***postData***(WeChatProperty.REFUND_URL, xml, WeChatProperty.MCH_ID, WeChatProperty.SSL_URL);
//把得到的返回值xml转map
Map<String, String> returnMap = WXPayUtil.xmlToMap(returnXml);
if (returnMap.get("return_code").equals(ResultCode.SUCCESS)) {
return new WeChatRefundResponse(ResultCode.SUCCESS);
}else {
return new WeChatRefundResponse(ResultCode.FAILURE);
}
}
private String generateRefundParams(WeChatRefundCommand command) throws Exception {
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", WeChatProperty.APP_ID);
packageParams.put("mch_id", WeChatProperty.MCH_ID);
packageParams.put("nonce_str", WeChatPayUtil.generateNonceStr());
packageParams.put("out_trade_no", command.getOutTradeNo());
packageParams.put("out_refund_no", WeChatPayUtil.generateTradeId());
packageParams.put("total_fee", command.getTotalFee().toString());
packageParams.put("refund_fee", command.getRefundFee().toString());
String sign = WXPayUtil.generateSignature(packageParams, WeChatProperty.KEY);
packageParams.put("sign", sign);
return WXPayUtil.mapToXml(packageParams);
}
/**
* 通过Https往API post xml数据
*
* @param url API地址
* @param xmlObj 要提交的XML数据对象
* @param mchId 商户ID
* @param certPath 证书位置
* @return
*/
public static String ***postData***(String url, String xmlObj, String mchId, String certPath) {
// 加载证书
try {
initCert(mchId, certPath);
} catch (Exception e) {
e.printStackTrace();
}
String result = null;
HttpPost httpPost = new HttpPost(url);
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
// 根据默认超时限制初始化requestConfig
requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
// 设置请求器的配置
httpPost.setConfig(requestConfig);
try {
HttpResponse response = null;
try {
response = httpClient.execute(httpPost);
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity = response.getEntity();
try {
result = EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
} finally {
httpPost.abort();
}
return result;
}
/**
* 加载证书
*
* @param mchId 商户ID
* @param certPath 证书位置
* @throws Exception
*/
public static void initCert(String mchId, String certPath) throws Exception {
// 证书密码,默认为商户ID
String key = mchId;
// 证书的路径
String path = certPath;
// 指定读取证书格式为PKCS12
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// 读取本机存放的PKCS12证书文件
ClassPathResource cp = new ClassPathResource("apiclient_cert.p12");
InputStream instream = cp.getInputStream();
try {
// 指定PKCS12的密码(商户ID)
keyStore.load(instream, key.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(sslcontext, new String[] {"TLSv1"}, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
总结
微信退款个人觉得没有支付宝退款简单,就获取证书这方面就较为复杂,包括加载证书进行退款。希望代码可以对码农们有些帮助!