转载请注明出处:https://blog.csdn.net/Strugglein/article/details/81186738
之前说了微信支付的支付和回调,这篇说一下微信支付的退款以及退款的回调
以下内容可能会很长,请找个安静的小角落好好吸收一波~~~
1.退款
如果订单已经支付了想要退款的话,根据商户的后台提出退款的申请,通过以下代码来向微信提出退款申请:
public Map<Object, Object> wxRefund(Long orderId) throws Exception {
HashMap<String, Object> properties = WeChatPayUtil.getProperties();
Map resultMap = new HashMap<Object, Object>();
UserOrder order = userOrderMapper.selectById(orderId);
String outRefundNo = GetConstantsUtil.USER_REFUND_PREFIX + String.valueOf(System.currentTimeMillis());
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", String.valueOf(properties.get("wx.appid")));//应用id
packageParams.put("mch_id", String.valueOf(properties.get("wx.mch_id")));//商户号
packageParams.put("nonce_str", WeChatPayToolsUtil.CreateNoncestr());//随机字符串
packageParams.put("out_trade_no", String.valueOf(orderId));//订单号
packageParams.put("out_refund_no", outRefundNo);//退款单号
packageParams.put("total_fee", String.valueOf(order.getFee()));//订单总金额
packageParams.put("refund_fee", String.valueOf(order.getFee()));//退款总金额
packageParams.put("op_user_id", String.valueOf(properties.get("wx.mch_id")));//商户号
packageParams.put("notify_url", GetConstantsUtil.WECHAT_REFUNDNOTIFYURL);//回调地址
String sign = WeChatPayToolsUtil.signMd5_2(packageParams, String.valueOf(properties.get("wx.partnerKey")));
logger.debug("--sign--=" + sign);
String xml = null;
try {
xml = WeChatPayToolsUtil.createXML(packageParams, sign.toUpperCase());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
logger.debug("--xml-=" + xml);
String retur = null;
try {
retur = ClientCustomSSL.doRefund(GetConstantsUtil.WECHAT_REFUNDURL, xml);
logger.debug("结果为" + retur);
} catch (Exception e) {
e.printStackTrace();
}
int updateResult = -1;
if (!StringUtils.isEmpty(retur)) {
Map map = WeChatPayToolsUtil.parseXmlToMap(retur);
logger.debug("返回的结果为:+++_+++" + map.toString());
if ("SUCCESS".equals(map.get("return_code"))) {
if ("SUCCESS".equals(map.get("result_code"))) {
//这里是退款成功的返回结果
} else if ("FAIL".equals(map.get("result_code"))) {
resultMap.put("err_code", map.get("err_code"));
resultMap.put("err_code_des", map.get("err_code_des"));
}
}
}
return resultMap;
}
以上代码为退款所需要的代码其中需要的工具类在我的第一篇文章中有https://blog.csdn.net/Strugglein/article/details/81143244
但是微信退款需要一个证书,这个证书在微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->证书下载
这里去下载,下载完成后在配置文件中配置好地址然后根据引入到以下的工具类中
并且将数据以及请求地址作为参数请求这个工具类然后会返回结果进行处理,这个结果是是否请求成功的结果并不代表是否退款成功 详细参数根据微信的api来进行获取自己需要的参数,微信退款api:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_4&index=6
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.core.io.ClassPathResource;
import sun.rmi.runtime.Log;
public class ClientCustomSSL {
public static String doRefund(String url, String data) throws Exception {
HashMap<String, Object> properties = WeChatPayUtil.getProperties();
String mchId = String.valueOf(properties.get("wx.mch_id"));
KeyStore keyStore = KeyStore.getInstance("PKCS12");
ClassPathResource classPathResource = new ClassPathResource("apiclient_cert.p12");
FileInputStream is = new FileInputStream(new File(String.valueOf(properties.get("wx.refund_cert"))));
try {
keyStore.load(is, mchId.toCharArray());//密码MCHID
} finally {
is.close();
}
// Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, mchId.toCharArray())// 密码MCHID
.build();
// Allow TLSv1 protocol only
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(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();
}
}
}
2.退款回调
接下来就是退款回调的接口了,通过上面的提出退款的请求后,微信受理后会异步回调这个接口然后来进行通知,
public String wxRefundNotify(String result) {
HashMap<String, Object> properties = WeChatPayUtil.getProperties();
Map<String, String> m = new HashMap<String, String>();// 解析xml成map
if (m != null && !"".equals(m)) {
try {
m = WeChatPayToolsUtil.doXMLParse(result);
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
// 过滤空 设置 TreeMap
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
String resXml = "";
if ("SUCCESS".equals((String) packageParams.get("return_code"))) {
String req_info = (String) packageParams.get("req_info");
String returnInfo = "";
try {
returnInfo = AESUtil.decryptData(req_info);
logger.debug(returnInfo);
} catch (Exception e) {
e.printStackTrace();
}
/*
解析xml成map
*/
Map<String, String> m2 = new HashMap<String, String>();
if (m2 != null && !"".equals(m2)) {
try {
m2 = WeChatPayToolsUtil.doXMLParse(returnInfo);
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
/*
// 过滤空 设置 TreeMap
*/
SortedMap<Object, Object> packageParams2 = new TreeMap<Object, Object>();
Iterator it2 = m2.keySet().iterator();
while (it2.hasNext()) {
String parameter2 = (String) it2.next();
String parameterValue2 = m2.get(parameter2);
String v2 = "";
if (null != parameterValue2) {
v2 = parameterValue2.trim();
}
packageParams2.put(parameter2, v2);
}
logger.info("info信息为" + packageParams2.toString());
// 如果返回成功 商户号,商户订单号,商户退款单号,订单金额,订单退款金额,退款状态,资金来源,退款入账账户
String mch_id = (String) packageParams.get("mch_id");
String out_trade_no = (String) packageParams2.get("out_trade_no");
String out_refund_no = (String) packageParams2.get("out_refund_no");
String total_fee = (String) packageParams2.get("total_fee");
String settlement_refund_fee = (String) packageParams2.get("settlement_refund_fee");
String refund_status = (String) packageParams2.get("refund_status");
String refund_account = (String) packageParams2.get("refund_account");
String refund_recv_accout = (String) packageParams2.get("refund_recv_accout");
//校验商户号,如果正确
int updateResult = -1;
if (properties.get("wx.mch_id").equals(mch_id)) {
if ("SUCCESS".equals(refund_status)) {
//这里是返回数据ok
//在这里处理业务数据
}
}
if (updateResult == 1) {
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[参数错误]]></return_msg>" + "</xml> ";
}
} else // 如果微信返回支付失败,将错误信息返回给微信
{
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[交易失败]]></return_msg>" + "</xml> ";
}
logger.info("response结果为" + resXml);
return resXml;
}
这个接口用来接收微信的退款回调的,接收后根据返回的结果处理业务,会返回一些比如退款退到哪里以及用什么支付的一些内容,根据微信api的字段来获取想得到的数据,微信退款回调api:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_16&index=11
3.总结
在这里微信支付的一些操作就做完了,微信的坑本来就多,解决的方法就是不要慌慢慢来,总会一点一点的填平的,如果哪里遇到还有什么难以吸收的地方,可以联系我,一定知无不言言无不尽,如果还有哪里做的不是太ok的地方,欢迎大佬前来指教,学习才能进步嘛,如果不想一点一点拷代码的话,我已经将一套的代码上传到了我的下载里:https://download.csdn.net/download/strugglein/10560640 可以移步到这里支持我一下,根据博文和代码一起耐性的看一下总会出来的,希望大家都可以通过code来得到自己想要的一些东西,致所有和我一样的猿人们.
虚心的去学习,自信的去工作~