玩转小程序支付之退款

完成小程序支付和保存支付通知内容之后,接下来就是退款啦

官方文档: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,因为证书是微信认证过的商户独有的。


码字不易,如果觉得有帮助,一定要给我点赞哟~~

不然信不信我砸了你家灯,半夜偷亲你 ( ̄ε  ̄) !!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容