微信小程式實現退款,Java版。
阿新 • • 發佈:2021-02-05
目錄
一、準備工作
要實現退款,需要準備很多東西。
小程式ID(APPID)
商戶號(mch_id)
隨機字串(nonce_str)
微信訂單號(transaction_id)
商戶退款單號(out_refund_no)
訂單金額(total_fee)
退款金額(refund_fee)
簽名(sign)通過商戶證書金鑰生成
商戶證書:是從微信商戶平臺-》賬戶設定-》API安全 中下載的
Tip:其中的微信的訂單號、訂單金額都在訂單裡,在: https://blog.csdn.net/weixin_46030885/article/details/112734175中有提到支付成功後如何實現回撥,如何存支付訂單。
二、程式碼編寫
1.將大部分常用的資料封裝在WechatConstant中
Tip:這個WechatConstant在下邊的程式碼中會用到,而且以後修改資訊可直接在這裡修改,別處的程式碼就不用動了
public class WechatConstant {
public final static String MCH_ID = "****************"; //商戶號
public final static String MCH_KEY = "***************"; //商戶金鑰
public final static String APPID = "*****************"; //appid
public final static String SECRET = "****************"; //小程式金鑰
public final static String KEY = "*******************"; //商戶證書金鑰
}
2.controller
Tip:這個controller主要是構建引數的,將那些APPID、商戶號等東西放進map裡,在後邊的service中要轉成xml格式
@ApiOperation("退款")
@RequestMapping(value = "/refund", method = {RequestMethod.GET})
public Res refund(HttpServletRequest request,
@RequestParam("openid") String openid,
@RequestParam("activityid")int activityid,
@RequestParam("memberid") int memberid) throws Exception {
//先將訂單資訊查出來 這裡的訂單就是上邊說的支付訂單,我的是通過openid和一個activityid查出來的,自己可根據業務邏輯修改。
QueryWrapper<Wxpaynotifyvo> wxPayNotifyVOQueryWrapper = new QueryWrapper<>();
wxPayNotifyVOQueryWrapper.eq("openid", openid);
wxPayNotifyVOQueryWrapper.eq("activityid",activityid);
Wxpaynotifyvo wxPayNotifyVO = this.wxPayService.getBaseMapper().selectOne(wxPayNotifyVOQueryWrapper);
//構建引數
Map<String, String> dataMap = new HashMap<>();
//小程式ID
dataMap.put("appid", WechatConstant.APPID);
//商戶號
dataMap.put("mch_id", WechatConstant.MCH_ID);
//隨機字串
dataMap.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
//微信訂單號
dataMap.put("transaction_id", wxPayNotifyVO.getTransactionid());
//商戶退款單號
Date now = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//可以方便地修改日期格式
String outRefundNo = "NO" + dateFormat.format(now);
dataMap.put("out_refund_no", outRefundNo);
//訂單金額
dataMap.put("total_fee", wxPayNotifyVO.getTotalfee());
//退款金額
dataMap.put("refund_fee", wxPayNotifyVO.getTotalfee());
//商戶證書金鑰,生成簽名
String sign = WXPayUtil.generateSignature(dataMap, WechatConstant.KEY);
dataMap.put("sign", sign);
//這個是將報名表裡的資料刪除
int i = applymanService.deleteApplyman(openid, activityid, memberid);
//這個不是
this.wxPayService.refound(dataMap);
Res res = new Res();
res.setCode(0);
res.setMsg("退款成功!");
return res;
}
3.service
Tip:在這裡真正實現退款,裡邊要用到一個商戶證書,上邊提到過,需要在微信商戶平臺下載的,大概就長這個樣子:
/**
* 退款
*
* @param dataMap
*/
@Override
public void refound(Map<String, String> dataMap) {
try {
//將傳來的map轉xml
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
for (String key : dataMap.keySet()) {
String value = "<![CDATA[" + dataMap.get(key) + "]]>";
sb.append("<" + key + ">" + value + "</" + key + ">");
System.out.println();
}
sb.append("</xml>");
String xmlString = sb.toString();
doRefoud(dataMap.get("mch_id"), "https://api.mch.weixin.qq.com/secapi/pay/refund", xmlString);
} catch (Exception e) {
e.printStackTrace();
}
//退款之後將wxpaynotifyvo中的資料刪除,防止下次報名活動時與上次資料重複
QueryWrapper<Wxpaynotifyvo> wxpaynotifyvoQueryWrapper = new QueryWrapper<>();
wxpaynotifyvoQueryWrapper.eq("transactionid",dataMap.get("transaction_id"));
int delete = this.baseMapper.delete(wxpaynotifyvoQueryWrapper);
}
private static String doRefoud(String mch_id, String url, String xmlString) throws Exception {
//證書 是從微信商戶平臺-》賬戶設定-》 API安全 中下載的
KeyStore keyStore = KeyStore.getInstance("PKCS12");
//我想的是把證書傳到伺服器上,沒寫出來
//FileInputStream inputStream = new FileInputStream(new File("src\\main\\resources\\apiclient_cert.p12"));
//據說這樣寫打包後也可以找到,就放在resources裡了
ClassPathResource classPathResource = new ClassPathResource("apiclient_cert.p12");
InputStream inputStream = classPathResource.getInputStream();
try {
//這裡寫密碼,預設是MCHID
keyStore.load(inputStream, WechatConstant.MCH_ID.toCharArray());
} finally {
inputStream.close();
} //這裡寫密碼
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, WechatConstant.MCH_ID.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
//請求路徑
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(xmlString,"UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
HttpEntity entity = response.getEntity();
//接受到返回資訊
String jsonStr = EntityUtils.toString(response.getEntity(),"UTF-8");
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpClient.close();
}
return null;
}
Tip:退款之前先要實現支付,因為支付訂單裡邊的引數是必須的,本來支付退款應該寫在一起,但是東西太多所以分開了。這篇小程式退款是和前邊寫的微信支付是一個專案裡的,可以結合著一起看比較完整。連線:https://blog.csdn.net/weixin_46030885/article/details/112734175
歡迎批評糾正 ~ _ ~