APP支付 + 退款(JAVA實現)

首先,你得先有微信開發平臺帳號密碼還須要開通應用,而後還有微信服務商平臺商戶版帳號(這些我都是給產品經理拿的)html

其次我認爲你先去看一看微信開發平臺的文檔!  https://pay.weixin.qq.com/wiki/doc/api/index.html前端

 

 這裏有不少種支付,我就採用APP支付來講了(會了APP支付其實H5支付都差很少的!)git

 

 

進來後是這樣的,隨便看看'APP支付那幾篇文章'講的流程!,看完後知道大概了就能夠看看'API列表了'github

 

 

 

咱們後臺開發須要關注的就是這三個API了!後端

 

那我仍是簡單介紹一下APP支付的一個業務流程吧(其實文檔裏簡述的了,我就直接貼圖了!)api

 

 

這些圈圈起來的流程步驟,就是咱們後臺要作的了,其餘的都是由移動端來實現的,咱們能夠不理會,還有步驟6查詢訂單支付結果,這個可作可不作吧,爲了系統更安全些更慎重些也能夠去實現,不過我就沒有實現了安全

 

下面就說一下如何對接這個所謂的第三方接口,其實就是跟前端來調用咱們後端接口是同樣的,咱們在寫接口文檔時,有請求地址,請求參數,返回數據以及返回數據格式這4樣!微信

只要提供這4種東西,前端就能夠來對接咱們後臺接口啦!因此,同個道理的,此次是由咱們後臺人員去請求微信提供的接口!微信開發

 

因此文檔上都有提供的了,咱們只須要用httpclient來想微信接口那邊發送同步請求獲取返回結果數據便可,這樣聽起來貌似很簡單!不過還真不是很簡單,不少坑的,畢竟是騰訊的文檔!mybatis

而後要注意的首先是請求參數,請求參數是否必填這個若是是否的話我就建議不用填上去了,而後簽名參數也要去看文檔,如何生成簽名,還有,參數是要以xml格式形式發送過去,

並且返回結果也是以xml返回回來,因此和微信對接的交互就是xml,這點有點蛋疼呀!

好了,上面說了該怎麼去請求第三方接口,想必你們有點懵吧,不知道該如何下手,其實上面的那個請求方式有點難度,小白能夠忽略上面那套方式,直接使用微信支付的一個開源jar!

 

對 你沒看錯,就這一個,這個jar包裏面已經封裝好了咱們如何獲取簽名,如何驗籤等api方法,並且還不須要咱們去將參數轉化成xml格式,它已經封裝好了一切了,因此很是方便!

這個jar包能夠在這個地址去下載http://www.mvnjar.com/com.github.liyiorg/weixin-popular/2.8.14/detail.html

 

好了,那上面的介紹看完還有微信jar拿到手後,如今就能夠開始來實現了! 我就直接亮代碼了!

 

複製代碼
  1 /**
  2  * @description:微信支付JAVA-SDK: APP支付,退款
  3  * @author:小黑
  4  */
  5 @Service
  6 public class WechatPayService {
  7     private static final Logger LOGGER = LoggerFactory.getLogger(WechatPayService.class);
  8     
  9     /************ 微信開放平臺配置  ***************/
 10     
 11     /** APPID */
 12     private static final String APPID = ""; 
 13     
 14     /** 商戶號 */
 15     private static final String MCH_ID = "";  
 16     
 17     /** 密鑰 */
 18     private static final String PRIVATE_KEY = "";
 19     
 20     /** 用戶訂單支付結果異步通知url */
 21     private static final String NOTIFY_URL = "";
 22     
 23     /** 商戶支付證書路徑 */
 24     private static final String API_CLIENT_CERT_PATH = "";
 25     
 26     // 加載商戶支付證書文件;
 27     static {
 28         LocalHttpClient.initMchKeyStore(MCH_ID, API_CLIENT_CERT_PATH);
 29     }
 30     
 31     /**
 32      * @description:使用微信支付-APP支付方式-統一下單;
 33      * @return 支付參數,若是支付失敗則返回null
 34      * @author:Fanhaojian
 35      */
 36     public MchPayApp orderAppPay(PayLog payLog) {
 37         
 38         Unifiedorder unifiedorder = new Unifiedorder();
 39         
 40         /** APPID */
 41         unifiedorder.setAppid(APPID);
 42         
 43         /** 商戶號 */
 44         unifiedorder.setMch_id(MCH_ID);
 45         
 46         /** 隨機字符串 */
 47         unifiedorder.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));
 48         
 49         /** 商品描述 */
 50         unifiedorder.setBody(payLog.getPayCode());
 51         
 52         /** 商戶訂單號 */
 53         unifiedorder.setOut_trade_no(payLog.getPayCode());
 54         
 55         /** 訂單總金額 */
 56         unifiedorder.setTotal_fee(payLog.getPayPrice().multiply(new BigDecimal(100)).intValue() + "");   // 訂單總金額,單位爲分;
 57         
 58         /** 用戶端請求IP地址 */
 59         unifiedorder.setSpbill_create_ip(IpUtils.getClientIp());
 60         
 61         /** 異步通知回調地址 */
 62         unifiedorder.setNotify_url(NOTIFY_URL);
 63         
 64         /** 交易類型 */
 65         unifiedorder.setTrade_type("APP");
 66         
 67         LOGGER.warn("微信APP支付--(簽名前):" + XMLConverUtil.convertToXML(unifiedorder));
 68         
 69         /** 獲取簽名 */
 70         UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, PRIVATE_KEY);
 71         
 72         LOGGER.warn("微信APP支付--支付統一下單接口請求狀態(return_code):" + unifiedorderResult.getReturn_code());
 73         LOGGER.warn("微信APP支付--支付統一下單接口請求狀態(return_msg):" + unifiedorderResult.getReturn_msg());
 74         LOGGER.warn("微信APP支付--支付統一下單接口請求狀態(result_code):" + unifiedorderResult.getResult_code());
 75         LOGGER.warn("微信APP支付--支付請求參數封裝(簽名後):" + XMLConverUtil.convertToXML(unifiedorder));
 76         LOGGER.warn("微信APP支付--支付統一下單接口返回數據:" + FastJSONUtils.getJsonHelper().toJSONString(unifiedorderResult));
 77         
 78         // 下單結果驗籤; 
 79         if(unifiedorderResult.getSign_status() != null && unifiedorderResult.getSign_status()) {
 80             LOGGER.warn("微信APP支付驗籤成功");
 81             return PayUtil.generateMchAppData(unifiedorderResult.getPrepay_id(), APPID, MCH_ID, PRIVATE_KEY);
 82         }
 83         return null;
 84     }
 85     
 86     /**
 87      * @description:微信退款業務封裝(支付押金退還);
 88      * @param   PayLog order:支付訂單信息
 89      *           Double refundAmount:退款金額
 90      * @return 微信退款接口返回數據  true 退款成功  false 退款失敗
 91      * @author:FanHaoJian
 92      */
 93     public Boolean refundOrder(PayLog order, Double refundAmount) {
 94         
 95         // 調用微信支付退款接口;
 96         SecapiPayRefund payRefund = new SecapiPayRefund();
 97         payRefund.setAppid(APPID);
 98         payRefund.setMch_id(MCH_ID);
 99         payRefund.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));
100         payRefund.setOut_trade_no(order.getPayCode());//支付訂單號
101         payRefund.setOut_refund_no(order.getRefundCode());//退款單號
102         payRefund.setTotal_fee(order.getPayPrice().multiply(new BigDecimal(100)).intValue());//原訂單金額,單位:分;
103         payRefund.setRefund_fee(new BigDecimal(refundAmount).multiply(new BigDecimal(100)).intValue());//退款訂單金額,單位:分;
104         
105         SecapiPayRefundResult refundResult = PayMchAPI.secapiPayRefund(payRefund, PRIVATE_KEY);
106         
107         // 微信支付退款接口返回數據驗籤;
108         if(refundResult.getSign_status() != null && refundResult.getSign_status()) {
109             LOGGER.warn("微信退款接口--接口請求狀態(return_code):" + refundResult.getReturn_code());
110             LOGGER.warn("微信退款接口--接口請求狀態(return_msg):" + refundResult.getReturn_msg());
111             
112             // 退款信息提交成功;
113             if("SUCCESS".equals(refundResult.getReturn_code())) {
114                 LOGGER.warn("微信退款接口--接口請求狀態(result_code):" + refundResult.getResult_code());
115                 LOGGER.warn("微信退款接口--接口請求狀態(err_code):" + refundResult.getErr_code());
116                 LOGGER.warn("微信退款接口--接口請求狀態(err_code_des):" + refundResult.getErr_code_des());
117                 
118                 return Boolean.TRUE;
119             }
120         }
121         
122         return Boolean.FALSE;
123     }
124 }
複製代碼

 

在項目建一個sdk包,而後統一放入sdk,相似這樣!

而後建立一個微信支付SDK,將上面代碼複製過去,而後看一遍代碼裏的方法流程,看明白後在改改裏面的代碼!

 

而後我簡單介紹一下上面的微信支付SDK吧,裏面有兩個方法,一個是統一下單,一個是退款!

統一下單返回的數據就是要拿給移動端的簽名數據,退款返回的數據就是true和false,沒什麼判斷成功仍是失敗就好了,成功該作什麼,失敗該作什麼!

 

OK! 如今說完了統一下單和退款後,還有一個支付通知結果的API,也就是異步通知了!若是你看完了那篇流程圖,你就會知道,當移動端調起支付而且支付成功後,微信後臺那邊會向咱們這邊後臺發送一個請求過來!

固然微信那邊發送請求過來咱們這邊的接口,我也直接亮代碼了!

 

複製代碼
 1 /**
 2  * @description:微信支付異步通知請求URL
 3  * @author:小黑
 4  */
 5 public class WechatOrderNotify extends ActionSupport {
 6     private static final Logger LOGGER = LoggerFactory.getLogger(WechatOrderNotify.class);
 7     private static final long serialVersionUID = 1L;
 8     
 9     /** 密鑰 */
10     private static final String PRIVATE_KEY = "";
11     
12     /** 定義應答變量 */
13     private String xml;
14     
15     @Override
16     public String wechatOrderNotify() throws Exception {
17         
18         // 解析微信支付異步通知請求參數;
19         HttpServletRequest request = ServletActionContext.getRequest();
20         String xml = StreamUtils.copyToString(request.getInputStream(), Charset.forName("utf-8"));
21         Map<String, String> params = XMLConverUtil.convertToMap(xml);
22         MchPayNotify payNotify = XMLConverUtil.convertToObject(MchPayNotify.class, xml);
23         
24         /** 打印日誌信息 */
25         LOGGER.warn("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$---進入微信支付異步通知請求接口---$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
26         LOGGER.warn("微信支付用戶訂單支付結果異步通知請求參數(xml):" + params);
27         LOGGER.warn("微信支付用戶訂單支付結果異步通知請求參數(map):" + params);
28         LOGGER.warn("return_code:" + payNotify.getReturn_code());
29         LOGGER.warn("return_msg:" + params.get("return_msg"));
30         
31         /** 校驗支付成功仍是失敗 */
32         if("SUCCESS".equals(payNotify.getReturn_code())) {
33             
34             /** 獲取微信後臺返回來的異步通知參數 */
35             String outTradeNo = payNotify.getOut_trade_no();  // 用戶訂單號;
36             String tradeNo = payNotify.getTransaction_id();   // 微信交易號;
37             String tradeStatus = payNotify.getResult_code();  // 微信支付狀態;
38             Integer totalFee = payNotify.getTotal_fee();      // 支付金額
39             
40             /** 獲取驗簽結果 true說明驗籤成功   false說明驗籤失敗 */
41             boolean flag = SignatureUtil.validateSign(params, PRIVATE_KEY);
42             
43             /** 打印日誌信息 */
44             LOGGER.warn("微信支付--APP支付方式支付用戶訂單異步通知訂單號(out_trade_no):" + outTradeNo);
45             LOGGER.warn("微信支付--APP支付方式支付用戶訂單異步通知交易號(trade_no):" + tradeNo);
46             LOGGER.warn("微信支付--APP支付方式支付用戶訂單異步通知交易狀態(result_code):" + tradeStatus);
47             LOGGER.warn("微信支付--APP支付方式支付用戶訂單異步通知支付金額(total_fee):" + totalFee);
48             LOGGER.warn("微信支付--APP支付方式支付用戶訂單異步通知驗籤狀態:" + flag);
49             
50             /** 根據訂單號獲取訂單支付信息: 支付狀態爲 '未支付' */
51             ...此處省略 根據訂單號去查訂單 我用hibernate的 大家可能用mybatis或者其餘,因此本身去查吧!
52             
53             /** 支付成功/處理訂單業務信息 */
54             if(flag && "SUCCESS".equals(tradeStatus) && order != null) {
55                 
56                 /** 更新訂單支付信息: */
57                 ...此處省略 根據本身項目的業務去處理邏輯!
58                 
59                 /** 封裝通知信息 */
60                 MchBaseResult baseResult = new MchBaseResult();
61                 baseResult.setReturn_code("SUCCESS");
62                 baseResult.setReturn_msg("OK");
63                 xml =  XMLConverUtil.convertToXML(baseResult);
64             
65             /** 支付成功 */
66             }else if(flag && "SUCCESS".equals(tradeStatus)){
67                 MchBaseResult baseResult = new MchBaseResult();
68                 baseResult.setReturn_code("SUCCESS");
69                 baseResult.setReturn_msg("OK");
70                 xml =  XMLConverUtil.convertToXML(baseResult);
71             
72             /** 支付失敗 */
73             }else {    
74                 MchBaseResult baseResult = new MchBaseResult();
75                 baseResult.setReturn_code("FAIL");
76                 baseResult.setReturn_msg("FAIL");
77                 xml =  XMLConverUtil.convertToXML(baseResult);
78             }
79         
80         /** 支付失敗 */    
81         }else {
82             MchBaseResult baseResult = new MchBaseResult();
83             baseResult.setReturn_code("FAIL");
84             baseResult.setReturn_msg("FAIL");
85             xml =  XMLConverUtil.convertToXML(baseResult);
86         }
87         LOGGER.warn("微信支付--APP支付方式支付用戶訂單異步通知返回數據:" + xml);
88         return Results.XML;
89     }
90     
91     public String getXml() {
92         return xml;
93     }
94 
95     public void setXml(String xml) {
96         this.xml = xml;
97     }
98 }
複製代碼

 

這裏也是直接招搬過去,而後改改代碼便可!須要注意的就是這個返回數據xml,你可能要本身定義一下,應答是要這種格式的:

相關文章
相關標籤/搜索