微信公衆號支付(二):統一下單

上一篇已經獲取到了用戶的OpenIdphp

這篇主要是調用微信公衆支付的統一下單APIjava

API地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1git

看文檔,主要流程就是把20個左右的參數封裝爲XML格式發送到微信給的接口地址,而後就能夠獲取到返回的內容了,若是成功裏面就有支付所須要的預支付IDapi

請求參數就不解釋了。數組

其中,隨機字符串:我用的是UUID去中劃線安全

1 public static String create_nonce_str() {
2       return UUID.randomUUID().toString().replace("-","");
3 }

商戶訂單號:每一個訂單號只能使用一次,因此用的是系統的訂單號加的時間戳。微信

總金額:不能爲0app

通知地址:微信支付成功或失敗回調給系統的地址dom

簽名:工具

 1 import java.io.Serializable;
 2 
 3 public class PayInfo  implements Serializable{
 4     
 5     private static final long serialVersionUID = 5637164279924222380L;
 6     private String appid;
 7     private String mch_id;
 8     private String device_info;
 9     private String nonce_str;
10     private String sign;
11     private String body;
12     private String attach;
13     private String out_trade_no;
14     private int total_fee;
15     private String spbill_create_ip;
16     private String notify_url;
17     private String trade_type;
18     private String openid;
19         
20     //下面是get,set方法       
21 }
 1     /**
 2      * 建立統一下單的xml的java對象
 3      * @param bizOrder 系統中的業務單號
 4      * @param ip 用戶的ip地址
 5      * @param openId 用戶的openId
 6      * @return
 7      */
 8     public PayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) {
 9         PayInfo payInfo = new PayInfo();
10         payInfo.setAppid(Constants.appid);
11         payInfo.setDevice_info("WEB");
12         payInfo.setMch_id(Constants.mch_id);
13         payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", ""));
14         payInfo.setBody("這裏是某某白米飯的body");
15         payInfo.setAttach(bizOrder.getId());
16         payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(new Date(), "MMddHHmmss")));
17         payInfo.setTotal_fee((int)bizOrder.getFeeAmount());
18         payInfo.setSpbill_create_ip(ip);
19         payInfo.setNotify_url(Constants.notify_url);
20         payInfo.setTrade_type("JSAPI");
21         payInfo.setOpenid(openId);
22         return payInfo;
23     }

獲取簽名:

 1     /**
 2      * 獲取簽名
 3      * @param payInfo
 4      * @return
 5      * @throws Exception
 6      */
 7     public String getSign(PayInfo payInfo) throws Exception {
 8         String signTemp = "appid="+payInfo.getAppid()
 9                  +"&attach="+payInfo.getAttach()
10                  +"&body="+payInfo.getBody()
11                  +"&device_info="+payInfo.getDevice_info()
12                  +"&mch_id="+payInfo.getMch_id()
13                  +"&nonce_str="+payInfo.getNonce_str()
14                  +"&notify_url="+payInfo.getNotify_url()
15                  +"&openid="+payInfo.getOpenid()
16                  +"&out_trade_no="+payInfo.getOut_trade_no()
17                  +"&spbill_create_ip="+payInfo.getSpbill_create_ip()
18                  +"&total_fee="+payInfo.getTotal_fee()
19                  +"&trade_type="+payInfo.getTrade_type()
20                  +"&key="+Constants.key; //這個key注意
21         
22        MessageDigest md5 = MessageDigest.getInstance("MD5");
23        md5.reset();
24        md5.update(signTemp.getBytes("UTF-8"));
25        String sign = CommonUtil.byteToStr(md5.digest()).toUpperCase();
26        return sign;
27     }

注意:上面的Constants.key取值在商戶號API安全的API密鑰中。

一些工具方法:獲取ip地址,將字節數組轉換爲十六進制字符串,將字節轉換爲十六進制字符串

 1   /**
 2      * 將字節數組轉換爲十六進制字符串
 3      * 
 4      * @param byteArray
 5      * @return
 6      */
 7     public static String byteToStr(byte[] byteArray) {
 8         String strDigest = "";
 9         for (int i = 0; i < byteArray.length; i++) {
10             strDigest += byteToHexStr(byteArray[i]);
11         }
12         return strDigest;
13     }
14 
15     /**
16      * 將字節轉換爲十六進制字符串
17      * 
18      * @param btyes
19      * @return
20      */
21     public static String byteToHexStr(byte bytes) {
22         char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
23         char[] tempArr = new char[2];
24         tempArr[0] = Digit[(bytes >>> 4) & 0X0F];
25         tempArr[1] = Digit[bytes & 0X0F];
26 
27         String s = new String(tempArr);
28         return s;
29     }
30     
31     /**
32      * 獲取ip地址
33      * @param request
34      * @return
35      */
36     public static String getIpAddr(HttpServletRequest request) {  
37         InetAddress addr = null;  
38         try {  
39             addr = InetAddress.getLocalHost();  
40         } catch (UnknownHostException e) {  
41             return request.getRemoteAddr();  
42         }  
43         byte[] ipAddr = addr.getAddress();  
44         String ipAddrStr = "";  
45         for (int i = 0; i < ipAddr.length; i++) {  
46             if (i > 0) {  
47                 ipAddrStr += ".";  
48             }  
49             ipAddrStr += ipAddr[i] & 0xFF;  
50         }  
51         return ipAddrStr;  
52     }  

這樣就獲取了簽名,把簽名與PayInfo中的其餘數據轉成XML格式,當作參數傳遞給統一下單地址。

1 PayInfo pi = pu.createPayInfo(bo,"10.204.3.32","22");
2 String sign = pu.getSign(pi);
3 pi.setSign(sign);

對象轉XML

 1    /**
 2      * 擴展xstream使其支持CDATA
 3      */
 4     private static XStream xstream = new XStream(new XppDriver() {
 5         public HierarchicalStreamWriter createWriter(Writer out) {
 6             return new PrettyPrintWriter(out) {
 7                 //增長CDATA標記
 8                 boolean cdata = true;
 9 
10                 @SuppressWarnings("rawtypes")
11                 public void startNode(String name, Class clazz) {
12                     super.startNode(name, clazz);
13                 }
14 
15                 protected void writeText(QuickWriter writer, String text) {
16                     if (cdata) {
17                         writer.write("<![CDATA[");
18                         writer.write(text);
19                         writer.write("]]>");
20                     } else {
21                         writer.write(text);
22                     }
23                 }
24             };
25         }
26     });
27     
28     public static String payInfoToXML(PayInfo pi) {
29         xstream.alias("xml", pi.getClass());
30         return xstream.toXML(pi);
31     }

xml轉Map

 1     @SuppressWarnings("unchecked")
 2     public static Map<String, String> parseXml(String xml) throws Exception {
 3         Map<String, String> map = new HashMap<String, String>();
 4 
 5         Document document = DocumentHelper.parseText(xml);
 6         Element root = document.getRootElement();
 7         List<Element> elementList = root.elements();
 8 
 9         for (Element e : elementList)
10             map.put(e.getName(), e.getText());
11         return map;
12     }    

下面就是調用統一下單的URL了

1   log.info(MessageUtil.payInfoToXML(pi).replace("__", "_"));
2   Map<String, String> map = CommonUtil.httpsRequestToXML("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>", ""));
3    log.info(map);
 1 public static Map<String, String> httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) {
 2         Map<String, String> result = new HashMap<>();
 3         try {
 4              StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr);
 5              result = MessageUtil.parseXml(buffer.toString());
 6         } catch (ConnectException ce) {
 7             log.error("鏈接超時:"+ce.getMessage());
 8         } catch (Exception e) {
 9             log.error("https請求異常:"+ece.getMessage());
10         }
11         return result;
12     }
httpsRequest()這個方法在第一篇中
上面獲取到的Map若是成功的話,裏面就會有
 1  String return_code = map.get("return_code");
 2   if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")){
 3     String return_msg = map.get("return_msg");
 4      if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {
 5        return "統一下單錯誤!";
 6      }
 7  }else{
 8    return "統一下單錯誤!";
 9  }
10         
11  String prepay_Id = map.get("prepay_id");

這個prepay_id就是預支付的ID。後面支付須要它。

相關文章
相關標籤/搜索