/***
* 申请退款完整业务流程逻辑
*
* @param transaction_id
* 微信订单号(优先使用)
* @param out_trade_no
* 商户订单号
* @param total_fee
* 订单总金额
* @param refund_fee
* 退款金额
* @return 退款结果(xml格式)
* @throws Exception
*/
public static String Run(String transaction_id, String out_trade_no,
String total_fee, String refund_fee)
throws Exception {
Log.info("Refund is processing...");
WxPayData data = new WxPayData();
if (transaction_id != null && !transaction_id.isEmpty())// 微信订单号存在的条件下,则已微信订单号为准
{
data.SetValue("transaction_id", transaction_id);
} else// 微信订单号不存在,才根据商户订单号去退款
{
data.SetValue("out_trade_no", out_trade_no);
}
data.SetValue("total_fee", Integer.parseInt(total_fee));// 订单总金额
data.SetValue("refund_fee", Integer.parseInt(refund_fee));// 退款金额
data.SetValue("out_refund_no", WxPayApi.GenerateOutTradeNo());// 随机生成商户退款单号
data.SetValue("op_user_id", WxPayConfig.MCHID);// 操作员,默认为商户号
WxPayData result = WxPayApi.Refund(data, 0);// 提交退款申请给API,接收返回数据
Log.info("Refund process complete, result : " + result.ToXml());
return result.ToPrintStr();
}
/**
*
* 申请退款
*
* @param WxPayData
* inputObj 提交给申请退款API的参数
* @param int timeOut 超时时间
* @return 成功时返回接口调用结果,其他抛异常
* @throws Exception
*/
public static WxPayData Refund(WxPayData inputObj, int timeOut)
throws Exception {
timeOut = (timeOut == 0 ? 6 : timeOut);
String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
// 检测必填参数
if (!inputObj.IsSet("out_trade_no")
&& !inputObj.IsSet("transaction_id")) {
throw new WxPayException(
"退款申请接口中,out_trade_no、transaction_id至少填一个!");
} else if (!inputObj.IsSet("out_refund_no")) {
throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!");
} else if (!inputObj.IsSet("total_fee")) {
throw new WxPayException("退款申请接口中,缺少必填参数total_fee!");
} else if (!inputObj.IsSet("refund_fee")) {
throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!");
} else if (!inputObj.IsSet("op_user_id")) {
throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!");
}
inputObj.SetValue("appid", WxPayConfig.APPID);// 公众账号ID
inputObj.SetValue("mch_id", WxPayConfig.MCHID);// 商户号
inputObj.SetValue("nonce_str",
UUID.randomUUID().toString().replaceAll("-", ""));// 随机字符串
inputObj.SetValue("sign", inputObj.MakeSign("MD5"));// 签名
String xml = inputObj.ToXml();
long start = System.currentTimeMillis();
Log.debug("Refund request : " + xml);
String response = HttpService.doRefund(xml, url);// 调用HTTP通信接口提交数据到API
Log.debug("Refund response : " + response);
long end = System.currentTimeMillis();
int timeCost = (int) ((end - start));// 获得接口耗时
// 将xml格式的结果转换为对象以返回
WxPayData result = new WxPayData();
result.FromXml(response);
ReportCostTime(url, timeCost, result);// 测速上报
return result;
}
//根据商户证书和秘钥(及商户MCHID)实现发送信息给微信服务端实现退款
public static String doRefund(String xml,String url) throws Exception {
/**
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(WxPayConfig.SSLCERT_PATH));//PKCS12文件在服务器磁盘中的目录
try {
keyStore.load(instream, WxPayConfig.SSLCERT_PASSWORD.toCharArray());//这里写密码..默认是你的MCHID
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, WxPayConfig.SSLCERT_PASSWORD.toCharArray())//这里也是写密码的
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
HttpPost httpost = new HttpPost(url); // 设置响应头信息
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(xml, "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();
}
}