1. 程式人生 > 其它 >微信小程式實現退款,Java版。

微信小程式實現退款,Java版。

技術標籤:java小程式

目錄


一、準備工作

要實現退款,需要準備很多東西。
小程式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
歡迎批評糾正 ~ _ ~