完成小程序支付和保存支付通知内容之后,接下来就是退款啦
官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
注意:
安全证书调用API时需要使用证书,所以我们需要下载证书,并放在服务器里某个位置
/*
* 密钥证书文件的存放路径
*/
public static final String KEY_PATH = "/wwwroot/web/wechat/apiclient_cert.p12";
代码如下:
----SpringBoot 的Controller
/**
* 申请退款
* @return
*/
@RequestMapping(value = "/refund", method = RequestMethod.GET)
@Transactional
public @ResponseBody Map<String, Object> refund(String id,String user) {
Map result = new HashMap<String,Object>();
String currTime = PayUtils.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayUtils.buildRandom(4) + "";
String nonceStr = strTime + strRandom;
String outRefundNo = "wx@re@"+PayUtils.getTimeStamp();
String outTradeNo = "";
ProfPayLog payLog = wxappOrderService.findByPayLogId(Long.valueOf(id));
DecimalFormat df = new DecimalFormat("######0");
String fee = String.valueOf(df.format((Double.valueOf(payLog.getTotalFee())*100)));
SortedMap packageParams = new TreeMap<String, String>();
packageParams.put("appid", appId);
packageParams.put("mch_id", mchId);//微信支付分配的商户号
packageParams.put("nonce_str", nonceStr);//随机字符串,不长于32位
packageParams.put("op_user_id", mchId);//操作员帐号, 默认为商户号
//out_refund_no只能含有数字、字母和字符_-|*@
packageParams.put("out_refund_no", outRefundNo);//商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
packageParams.put("out_trade_no", outTradeNo);//商户侧传给微信的订单号32位
packageParams.put("refund_fee", fee);
packageParams.put("total_fee", fee);
packageParams.put("transaction_id", payLog.getTransactionId());//微信生成的订单号,在支付通知中有返回
String sign = PayUtils.createSign(packageParams,key);
String refundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
String xmlParam="<xml>"+
"<appid>"+appId+"</appid>"+
"<mch_id>"+mchId+"</mch_id>"+
"<nonce_str>"+nonceStr+"</nonce_str>"+
"<op_user_id>"+mchId+"</op_user_id>"+
"<out_refund_no>"+outRefundNo+"</out_refund_no>"+
"<out_trade_no>"+outTradeNo+"</out_trade_no>"+
"<refund_fee>"+fee+"</refund_fee>"+
"<total_fee>"+fee+"</total_fee>"+
"<transaction_id>"+payLog.getTransactionId()+"</transaction_id>"+
"<sign>"+sign+"</sign>"+
"</xml>";
String resultStr = PayUtils.post(refundUrl, xmlParam);
//解析结果
try {
Map map = PayUtils.doXMLParse(resultStr);
String returnCode = map.get("return_code").toString();
if(returnCode.equals("SUCCESS")){
String resultCode = map.get("result_code").toString();
if(resultCode.equals("SUCCESS")){
ProfPayLog profPayLog = new ProfPayLog();
profPayLog.setCreatedAt(new Date());
profPayLog.setSource(payLog.getSource());
profPayLog.setTotalFee(payLog.getTotalFee());
profPayLog.setTradeNo(payLog.getTradeNo());
profPayLog.setTransactionId(map.get("refund_id").toString());
profPayLog.setUserId(user);
profPayLog.setType(ProfPayLog.Type.Refund);
profPayLog = wxappOrderService.save(profPayLog);
result.put("status", "success");
}else{
result.put("status", "fail");
}
}else{
result.put("status", "fail");
}
} catch (Exception e) {
e.printStackTrace();
result.put("status", "fail");
}
return result;
}
----PayUtils
public static String post(String url, String xmlParam){
StringBuilder sb = new StringBuilder();
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(KEY_PATH));
try {
keyStore.load(instream, "商户id".toCharArray());
} finally {
instream.close();
}
// 证书
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, "商户id".toCharArray())
.build();
// 只允许TLSv1协议
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
//创建基于证书的httpClient,后面要用到
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
HttpPost httpPost = new HttpPost(url);//退款接口
StringEntity reqEntity = new StringEntity(xmlParam);
// 设置类型
reqEntity.setContentType("application/x-www-form-urlencoded");
httpPost.setEntity(reqEntity);
CloseableHttpResponse response = client.execute(httpPost);
try {
HttpEntity entity = response.getEntity();
System.out.println(response.getStatusLine());
if (entity != null) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
String text="";
while ((text = bufferedReader.readLine()) != null) {
sb.append(text);
}
}
EntityUtils.consume(entity);
} catch(Exception e){
e.printStackTrace();
}finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
注意:商户id是指前面用到的mch_id,因为证书是微信认证过的商户独有的。
码字不易,如果觉得有帮助,一定要给我点赞哟~~
不然信不信我砸了你家灯,半夜偷亲你 ( ̄ε  ̄) !!!
网友评论