本demo基于微信扫码支付退款
官方地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
/**
*
* @author hubl
* @date 2020/1/14
* @param * @param json 1 退款信息
* @return com.qiang.base.page.JsonResult
*/
public JsonResult refund(JSONObject json) throws Exception {
Integer total_fee = json.getBigDecimal("total_fee").multiply(new BigDecimal("100")).setScale(2).intValue();
Integer refund_fee = json.getBigDecimal("refund_fee").multiply(new BigDecimal("100")).setScale(2).intValue();
HashMap<String, Object> map = new HashMap<>();
String appid = WxForm.appid;
String mch_id = WxForm.mch_id;
String nonce_str = WxUtils.createNonceStr();
String transaction_id = json.getString("transaction_id");
String out_refund_no = UtilUuId.get18UUID();
map.put("appid", appid);
map.put("mch_id", mch_id);
map.put("nonce_str", nonce_str);
map.put("sign_type", "MD5");
map.put("transaction_id", transaction_id);
map.put("out_refund_no",out_refund_no);
map.put("total_fee", total_fee.toString());
map.put("refund_fee", refund_fee.toString());
String stringA = WxUtils.formatBizQueryParaMap(map, false);//对参数按照key=value的格式,并按照参数名ASCII字典序排序
System.out.println(stringA);
String stringSignTemp = stringA + "&key=" + WxForm.key;//拼接API密钥
String sign = MdFive.MD5(stringSignTemp).toUpperCase();
System.out.println(sign);
String xml = "<xml>" +
"<appid>" + appid + "</appid>" +
"<mch_id>" + mch_id + "</mch_id>" +
"<nonce_str>" + nonce_str + "</nonce_str>" +
"<sign_type>MD5</sign_type>" +
"<transaction_id>"+transaction_id+"</transaction_id>"+
"<out_refund_no>"+out_refund_no+"</out_refund_no>"+
"<total_fee>"+total_fee+"</total_fee>"+
"<refund_fee>"+refund_fee+"</refund_fee>"+
"<sign>" + sign + "</sign>" +
"</xml>";
System.out.println(xml);
String createOrderURL = "https://api.mch.weixin.qq.com/secapi/pay/refund";//微信统一下单接口
try {
//预下单 获取接口地址
Map map1 = WebUtils.doRefund(mch_id,createOrderURL, xml);//注意了退款.p12证书在这里面配置,官方文档没有怎么详细说明,所以很多同学很头大。
String return_code = (String) map1.get("return_code");
String return_msg = (String) map1.get("return_msg");
if ("SUCCESS".equals(return_code) && "OK".equals(return_msg)) {
return JsonResult.ok("success").put("out_refund_no", out_refund_no);
} else {
System.out.println(JSONObject.toJSONString(map));
return JsonResult.error("统一退单接口出错");
}
} catch (Exception e) {
e.printStackTrace();
return JsonResult.error("统一退单接口出错");
}
}
退款逻辑代码
/**
*
* @param mchId 商户ID
* @param url 请求URL
* @param data 退款参数
* @return
* @throws Exception
*/
public static Map doRefund(String mchId, String url, String data) throws Exception {
/**
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");//证书格式
//这里自行实现我是使用数据库配置将证书上传到了服务器可以使用 FileInputStream读取本地文件
ClassPathResource cl = new ClassPathResource("xxx您的证书名称cert.p12");//基于linux系统,获取证书相对路径
try {
//这里写密码..默认是你的MCHID
keyStore.load(cl.getInputStream(), mchId.toCharArray());
} finally {
cl.getInputStream().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);
Map<String,Object> map = XMLUtils.parseXmlToList(jsonStr);
return map;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}