玩轉小程序支付之退款

完成小程序支付和保存支付通知內容以後,接下來就是退款啦php

官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4java

注意:web

調用API時須要使用證書,因此咱們須要下載證書,並放在服務器裏某個位置小程序

/*
* 密鑰證書文件的存放路徑
*/
public static final String KEY_PATH = "/wwwroot/web/wechat/apiclient_cert.p12";api

 代碼以下:服務器

----SpringBoot 的Controller

/**
	   * 申請退款
	   * @return
	   */
	  @RequestMapping(value = "/refund", method = RequestMethod.GET)
	  @Transactional
	  public @ResponseBody Map<String, Object> refund(String id,String user) {
	        Map<String,Object> 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<String, String> 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,由於證書是微信認證過的商戶獨有的。微信

相關文章
相關標籤/搜索