程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 微信支付(JSAPI),微信支付jsapi

微信支付(JSAPI),微信支付jsapi

編輯:JAVA綜合教程

微信支付(JSAPI),微信支付jsapi


最近客棧訂房,當然是需要微信支付的,官方微信支付文檔什麼的,只想說 去你媽的文檔

so, 經過兩天不懈的努力和網上大牛文檔,終於做出來了,下面具體來說說,希望能對各位看客有點幫助

 

放大招,直接上代碼

1. Configure.java 文件

1 package com.kzb.website.core.wechat.common; 2 3 import java.util.Calendar; 4 import java.util.Date; 5 6 import org.apache.commons.lang3.StringUtils; 7 8 public class Configure { 9 10 private static String token = null; 11 private static Date tokenTime = null; 12 private static String jsapiTicket = null; 13 private static Date jsapiTicketTime = null; 14 15 public static String MD5 = "MD5"; 16 public static String EMPTY = ""; 17 public static String SUCCESS = "SUCCESS"; 18 public static String HEX_FORMAT = "%02x"; 19 public static String TRADE_TYPE = "JSAPI"; 20 public static String MIDDLE_LINE = "-"; 21 public static String CHARTSET_UTF8 = "UTF-8"; 22 23 public static String NOTIFY_SUCCESS = "<xml>\n<return_code><![CDATA[SUCCESS]]></return_code>\n<return_msg><![CDATA[OK]]></return_msg>\n</xml>"; 24 public static String NOTIFY_FAIL = "<xml>\n<return_code><![CDATA[FAIL]]></return_code>\n<return_msg><![CDATA[ERROR]]></return_msg>\n</xml>"; 25 26 private static String key = "API密鑰(32位,在微信商戶平台下的API安全欄下)"; 27 // 微信分配的公眾號ID(開通公眾號之後可以獲取到) 28 private static String appID = "XXXXXXXXXXXXXX"; 29 private static String appSecret = "XXXXXXXXXXXXXX"; 30 // 微信支付分配的商戶號ID(開通公眾號的微信支付功能之後可以獲取到) 31 private static String mchID = "1349019501"; 32 // 機器IP 33 private static String ip = "127.0.0.1"; 34 35 // 以下是幾個API的路徑: 36 // 統一下單 37 public static String UNIFIEDORDER_API = "https://api.mch.weixin.qq.com/pay/unifiedorder"; 38 // access_token API 39 public static String TOKEN_API = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; 40 // 臨時票據API 41 public static String TICKET_API = "https://api.weixin.qq.com/cgi-bin/ticket/getticket"; 42 // 微信OPENID API 43 public static String OPENID_API = "https://api.weixin.qq.com/sns/oauth2/access_token"; 44 45 public static void setKey(String key) { 46 Configure.key = key; 47 } 48 49 public static void setAppID(String appID) { 50 Configure.appID = appID; 51 } 52 53 public static void setMchID(String mchID) { 54 Configure.mchID = mchID; 55 } 56 57 public static void setIp(String ip) { 58 Configure.ip = ip; 59 } 60 61 public static String getKey(){ 62 return key; 63 } 64 65 public static String getAppid(){ 66 return appID; 67 } 68 69 public static String getMchid(){ 70 return mchID; 71 } 72 73 public static String getIP(){ 74 return ip; 75 } 76 77 public static String getAppSecret() { 78 return appSecret; 79 } 80 81 public static void setAppSecret(String appSecret) { 82 Configure.appSecret = appSecret; 83 } 84 85 public static String getToken() { 86 return token; 87 } 88 89 public static void setToken(String token) { 90 Configure.token = token; 91 Configure.tokenTime = new Date(); 92 } 93 94 public static String getJsapiTicket() { 95 return jsapiTicket; 96 } 97 98 public static void setJsapiTicket(String jsapiTicket) { 99 Configure.jsapiTicket = jsapiTicket; 100 Configure.jsapiTicketTime = new Date(); 101 } 102 103 public static boolean checkToken() { 104 if (!StringUtils.isEmpty(Configure.token)) { 105 Calendar calendar = Calendar.getInstance(); 106 calendar.setTime(tokenTime); 107 calendar.add(Calendar.SECOND, 7200); 108 return calendar.before(new Date()); 109 } 110 return true; 111 } 112 113 public static boolean checkJsapiTicket() { 114 if (!StringUtils.isEmpty(Configure.jsapiTicket)) { 115 Calendar calendar = Calendar.getInstance(); 116 calendar.setTime(jsapiTicketTime); 117 calendar.add(Calendar.SECOND, 7200); 118 return calendar.before(new Date()); 119 } 120 return true; 121 } 122 } View Code

 

2. SignMD5.java文件

1 package com.kzb.website.core.wechat.common; 2 3 import java.io.UnsupportedEncodingException; 4 import java.security.MessageDigest; 5 import java.security.NoSuchAlgorithmException; 6 import java.util.Formatter; 7 import java.util.UUID; 8 9 import org.springframework.security.crypto.password.PasswordEncoder; 10 11 public class SignMD5 implements PasswordEncoder { 12 public static String byteToHex(final byte[] hash) { 13 Formatter formatter = new Formatter(); 14 for (byte b : hash) { 15 formatter.format(Configure.HEX_FORMAT, b); 16 } 17 String result = formatter.toString(); 18 formatter.close(); 19 return result; 20 } 21 22 @Override 23 public String encode(CharSequence charSequence) { 24 try { 25 MessageDigest crypt = MessageDigest.getInstance(Configure.MD5); 26 crypt.reset(); 27 crypt.update(charSequence.toString().getBytes(Configure.CHARTSET_UTF8)); 28 return byteToHex(crypt.digest()); 29 } catch (NoSuchAlgorithmException e) { 30 e.printStackTrace(); 31 } catch (UnsupportedEncodingException e) { 32 e.printStackTrace(); 33 } 34 return Configure.EMPTY; 35 } 36 37 @Override 38 public boolean matches(CharSequence charSequence, String encodedPassword) { 39 return encode(charSequence).equals(encodedPassword); 40 } 41 42 public String createNonceStr() { 43 return UUID.randomUUID().toString().replaceAll(Configure.MIDDLE_LINE,Configure.EMPTY); 44 } 45 46 public String createTimeStamp() { 47 return Long.toString(System.currentTimeMillis() / 1000); 48 } 49 50 } View Code

 

3. WechatNotify.java文件

1 package com.kzb.website.core.wechat.common; 2 3 import java.io.Serializable; 4 5 import javax.xml.bind.annotation.XmlRootElement; 6 7 @XmlRootElement(name="xml") 8 public class WechatNotify implements Serializable{ 9 10 private static final long serialVersionUID = 8047707600433551023L; 11 private String appid; 12 private String attach; 13 private String bank_type; 14 private String fee_type; 15 private String is_subscribe; 16 private String mch_id; 17 private String nonce_str; 18 private String openid; 19 private String out_trade_no; 20 private String result_code; 21 private String return_code; 22 private String sign; 23 private String sub_mch_id; 24 private String time_end; 25 private String total_fee; 26 private String trade_type; 27 private String transaction_id; 28 29 public String getAppid() { 30 return appid; 31 } 32 33 public void setAppid(String appid) { 34 this.appid = appid; 35 } 36 37 public String getAttach() { 38 return attach; 39 } 40 41 public void setAttach(String attach) { 42 this.attach = attach; 43 } 44 45 public String getBank_type() { 46 return bank_type; 47 } 48 49 public void setBank_type(String bank_type) { 50 this.bank_type = bank_type; 51 } 52 53 public String getFee_type() { 54 return fee_type; 55 } 56 57 public void setFee_type(String fee_type) { 58 this.fee_type = fee_type; 59 } 60 61 public String getIs_subscribe() { 62 return is_subscribe; 63 } 64 65 public void setIs_subscribe(String is_subscribe) { 66 this.is_subscribe = is_subscribe; 67 } 68 69 public String getMch_id() { 70 return mch_id; 71 } 72 73 public void setMch_id(String mch_id) { 74 this.mch_id = mch_id; 75 } 76 77 public String getNonce_str() { 78 return nonce_str; 79 } 80 81 public void setNonce_str(String nonce_str) { 82 this.nonce_str = nonce_str; 83 } 84 85 public String getOpenid() { 86 return openid; 87 } 88 89 public void setOpenid(String openid) { 90 this.openid = openid; 91 } 92 93 public String getOut_trade_no() { 94 return out_trade_no; 95 } 96 97 public void setOut_trade_no(String out_trade_no) { 98 this.out_trade_no = out_trade_no; 99 } 100 101 public String getResult_code() { 102 return result_code; 103 } 104 105 public void setResult_code(String result_code) { 106 this.result_code = result_code; 107 } 108 109 public String getReturn_code() { 110 return return_code; 111 } 112 113 public void setReturn_code(String return_code) { 114 this.return_code = return_code; 115 } 116 117 public String getSign() { 118 return sign; 119 } 120 121 public void setSign(String sign) { 122 this.sign = sign; 123 } 124 125 public String getSub_mch_id() { 126 return sub_mch_id; 127 } 128 129 public void setSub_mch_id(String sub_mch_id) { 130 this.sub_mch_id = sub_mch_id; 131 } 132 133 public String getTime_end() { 134 return time_end; 135 } 136 137 public void setTime_end(String time_end) { 138 this.time_end = time_end; 139 } 140 141 public String getTotal_fee() { 142 return total_fee; 143 } 144 145 public void setTotal_fee(String total_fee) { 146 this.total_fee = total_fee; 147 } 148 149 public String getTrade_type() { 150 return trade_type; 151 } 152 153 public void setTrade_type(String trade_type) { 154 this.trade_type = trade_type; 155 } 156 157 public String getTransaction_id() { 158 return transaction_id; 159 } 160 161 public void setTransaction_id(String transaction_id) { 162 this.transaction_id = transaction_id; 163 } 164 } View Code

 

4. WechatPayModel.java文件

1 package com.kzb.website.core.wechat.common; 2 3 import javax.xml.bind.annotation.XmlRootElement; 4 5 import org.springframework.security.crypto.password.PasswordEncoder; 6 7 @XmlRootElement(name = "XML") 8 public class WechatPayModel { 9 10 private String appid; 11 private String mch_id; 12 private String nonce_str; 13 private String body; 14 private String out_trade_no; 15 private String total_fee; 16 private String spbill_create_ip; 17 private String notify_url; 18 private String trade_type; 19 private String openid; 20 private String sign; 21 22 public String getAppid() { 23 return appid; 24 } 25 26 public void setAppid(String appid) { 27 this.appid = appid; 28 } 29 30 public String getMch_id() { 31 return mch_id; 32 } 33 34 public void setMch_id(String mch_id) { 35 this.mch_id = mch_id; 36 } 37 38 public String getNonce_str() { 39 return nonce_str; 40 } 41 42 public void setNonce_str(String nonce_str) { 43 this.nonce_str = nonce_str; 44 } 45 46 public String getOut_trade_no() { 47 return out_trade_no; 48 } 49 50 public void setOut_trade_no(String out_trade_no) { 51 this.out_trade_no = out_trade_no; 52 } 53 54 public String getTotal_fee() { 55 return total_fee; 56 } 57 58 public void setTotal_fee(String total_fee) { 59 this.total_fee = total_fee; 60 } 61 62 public String getSpbill_create_ip() { 63 return spbill_create_ip; 64 } 65 66 public void setSpbill_create_ip(String spbill_create_ip) { 67 this.spbill_create_ip = spbill_create_ip; 68 } 69 70 public String getNotify_url() { 71 return notify_url; 72 } 73 74 public void setNotify_url(String notify_url) { 75 this.notify_url = notify_url; 76 } 77 78 public String getTrade_type() { 79 return trade_type; 80 } 81 82 public void setTrade_type(String trade_type) { 83 this.trade_type = trade_type; 84 } 85 86 public String getBody() { 87 return body; 88 } 89 90 public void setBody(String body) { 91 this.body = body; 92 } 93 94 public String getSign() { 95 return sign; 96 } 97 98 public void setSign(String sign) { 99 this.sign = sign; 100 } 101 102 public String getOpenid() { 103 return openid; 104 } 105 106 public void setOpenid(String openid) { 107 this.openid = openid; 108 } 109 110 public void sign(PasswordEncoder encoder) { 111 StringBuilder stringBuilder = new StringBuilder(); 112 stringBuilder.append("appid=").append(getAppid()); 113 stringBuilder.append("&body=").append(getBody()); 114 stringBuilder.append("&mch_id=").append(getMch_id()); 115 stringBuilder.append("&nonce_str=").append(getNonce_str()); 116 stringBuilder.append("&notify_url=").append(getNotify_url()); 117 stringBuilder.append("&openid=").append(getOpenid()); 118 stringBuilder.append("&out_trade_no=").append(getOut_trade_no()); 119 stringBuilder.append("&spbill_create_ip=").append(getSpbill_create_ip()); 120 stringBuilder.append("&total_fee=").append(getTotal_fee()); 121 stringBuilder.append("&trade_type=").append(getTrade_type()); 122 stringBuilder.append("&key=").append(Configure.getKey()); 123 this.sign = encoder.encode(stringBuilder.toString()); 124 } 125 126 @Override 127 public String toString() { 128 return "<xml>" + 129 "<appid><![CDATA[" + appid + "]]></appid>" + 130 "<body><![CDATA[" + body + "]]></body>" + 131 "<mch_id><![CDATA[" + mch_id + "]]></mch_id>" + 132 "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str>" + 133 "<notify_url><![CDATA[" + notify_url + "]]></notify_url>" + 134 "<openid><![CDATA[" + openid + "]]></openid>" + 135 "<out_trade_no><![CDATA[" + out_trade_no + "]]></out_trade_no>" + 136 "<spbill_create_ip><![CDATA[" + spbill_create_ip + "]]></spbill_create_ip>" + 137 "<trade_type><![CDATA[" + trade_type + "]]></trade_type>" + 138 "<total_fee><![CDATA[" + total_fee + "]]></total_fee>" + 139 "<sign><![CDATA[" + sign + "]]></sign>" + 140 "</xml>"; 141 } 142 } View Code

 

5. WechatUtil.java文件

1 package com.kzb.website.core.wechat.common; 2 3 import java.io.DataInputStream; 4 import java.io.IOException; 5 6 import javax.servlet.http.HttpServletRequest; 7 8 import com.kzb.website.core.utils.XMLUtil; 9 10 public class WechatUtil { 11 12 /** 13 * 微信回調成功後 將 xml 轉換為 WechatNotify 對象 14 * 15 * @param request 16 * @return WechatNotify 對象 17 */ 18 public static WechatNotify getNotifyBean(HttpServletRequest request){ 19 try { 20 DataInputStream in = new DataInputStream(request.getInputStream()); 21 byte[] dataOrigin = new byte[request.getContentLength()]; 22 // 根據長度,將消息實體的內容讀入字節數組dataOrigin中 23 in.readFully(dataOrigin); 24 // 關閉數據流 25 in.close(); 26 // 從字節數組中得到表示實體的字符串 27 String xml = new String(dataOrigin); 28 // 將 xml 轉換為 WechatNotify 對象 29 Object object = XMLUtil.xmlToBean(WechatNotify.class, xml); 30 if (object != null && object instanceof WechatNotify) { 31 WechatNotify notify = (WechatNotify) object; 32 return notify; 33 } else {return null;} 34 } catch (IOException e) { 35 e.printStackTrace(); 36 return null; 37 } 38 } 39 } View Code

 

6. XMLUtil.java文件

1 package com.kzb.website.core.utils; 2 3 import java.io.StringReader; 4 5 import javax.xml.bind.JAXBContext; 6 import javax.xml.bind.JAXBException; 7 import javax.xml.bind.Unmarshaller; 8 9 public class XMLUtil { 10 11 /** 12 * 將 XML 字符串轉換為 Java 對象 13 * 14 * @param clazz 要轉換對象的 class 15 * @param xml 待轉換的 xml 16 * @return 轉換後的對象 17 */ 18 public static Object xmlToBean(Class<?> clazz, String xml) { 19 try { 20 JAXBContext jc = JAXBContext.newInstance(clazz); 21 Unmarshaller us = jc.createUnmarshaller(); 22 return us.unmarshal(new StringReader(xml)); 23 } catch (JAXBException e) { 24 e.printStackTrace(); 25 return null; 26 } 27 } 28 } View Code

 

7. pay_choose.jsp 頁面,這個頁面是一個支付選擇畫面,用來獲取code,和回調到支付畫面

1 <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 <!DOCTYPE html> 3 <html> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> 7 <title>支付選擇畫面</title> 8 <meta name="keywords" content="關鍵字,關鍵字"> 9 <meta name="description" content=""> 10 <style type="text/css"> 11 *{margin: 0;padding: 0;} 12 body{font-size:12px;font-family:"微軟雅黑";color:#666;} 13 </style> 14 </head> 15 <body> 16 <div > 17 <a href="javascript:wechat();">微信支付</a><br/><br/><br/> 18 <a href="javascript:ali();">支付寶支付</a> 19 </div> 20 <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> 21 <script type="text/javascript"> 22 function wechat(){ 23 var redirect_uri = "http://www.xxxxx.com/wxpay/payment.htm?hotelId=14501"; 24 var href = "https://open.weixin.qq.com/connect/oauth2/authorize?redirect_uri=" + encodeURIComponent(redirect_uri); 25 href += "&appid=wx73997299f6dba700&response_type=code&scope=snsapi_base"; 26 window.location.href = href; 27 } 28 function ali(){ 29 30 } 31 </script> 32 </body> 33 </html> View Code

 

8. wechat_pay.jsp 頁面

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"%>
 2 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 3 <!DOCTYPE html>
 4 <html>
 5 <head>
 6     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 8     <title>微信支付</title>
 9     <meta name="keywords" content="關鍵字,關鍵字">
10     <meta name="description" content="">
11 <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
12 <script type="text/javascript" charset="UTF-8" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
13 <script type="text/javascript">
14 function pay(){
15     //config
16     var appId = $('#appId').val();
17     var timeStamp = $('#timeStamp').val();
18     var nonceStr = $('#nonceStr').val();
19     var signature = $('#signature').val();
20     
21     var signType = $('#signType').val();
22     var pk = $('#package').val();
23     var paySign = $('#paySign').val();
24 
25     wx.config({
26         debug: false, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。
27         appId: appId, // 必填,公眾號的唯一標識
28         timestamp: timeStamp , // 必填,生成簽名的時間戳
29         nonceStr: nonceStr, // 必填,生成簽名的隨機串
30         signature: signature,// 必填,簽名,見附錄1
31         jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
32     });
33 
34     wx.ready(function(res){
35         // config信息驗證後會執行ready方法,所有接口調用都必須在config接口獲得結果之後,config是一個客戶端的異步操作,所以如果需要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則可以直接調用,不需要放在ready函數中。
36         wx.chooseWXPay({
37             timestamp: timeStamp, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付後台生成簽名使用的timeStamp字段名需大寫其中的S字符
38             nonceStr: nonceStr, // 支付簽名隨機串,不長於 32 位
39             package: pk, // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***)
40             signType: signType, // 簽名方式,默認為'SHA1',使用新版支付需傳入'MD5'
41             paySign: paySign, // 支付簽名
42             success: function (res) {
43                 location.href = 'http://www.xxxxxxx.net/success.htm';
44             },
45             cancel: function (res) {
46                 location.href = 'http://www.xxxxxxx.net/success.htm';
47             },
48             fail: function (res) {
49                 location.href = 'http://www.xxxxxxx.net/success.htm';
50             }
51         });
52     });
53 
54     wx.error(function (res) {
55         alert("error:" + JSON.stringify(res));
56     });
57 }
58 </script>
59 </head>
60 <body onload="pay()">
61     <h1>正在進行微信支付....
62         <br/>
63         <small>請不要關閉</small>
64     </h1>
65     <input id="appId" type="hidden" value="${start.appId}" /><br/>
66     <input id="timeStamp" type="hidden" value="${start.timestamp}" /><br/>
67     <input id="nonceStr" type="hidden" value="${start.nonceStr}" /><br/>
68     <input id="signature" type="hidden" value="${start.signature}" /><br/>
69     
70     <input id="signType" type="hidden" value="${pay.signType}" /><br/>
71     <input id="package" type="hidden" value="${pay.packageStr}" /><br/>
72     <input id="paySign" type="hidden" value="${pay.paySign}" /><br/>
73 </body>
74 </html>

 

9. WechatPayService.java 頁面

  1 package com.kzb.website.web.wechat;
  2 
  3 import java.util.HashMap;
  4 import java.util.Map;
  5 
  6 import org.apache.commons.lang3.StringUtils;
  7 import org.springframework.stereotype.Service;
  8 import org.springframework.ui.Model;
  9 import org.springframework.web.client.RestTemplate;
 10 
 11 import com.alibaba.fastjson.JSONArray;
 12 import com.fasterxml.jackson.databind.JsonNode;
 13 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 14 import com.kzb.website.core.wechat.common.Configure;
 15 import com.kzb.website.core.wechat.common.SignMD5;
 16 import com.kzb.website.core.wechat.common.WechatPayModel;
 17 
 18 @Service
 19 public class WechatPayService {
 20     SignMD5 encoder = new SignMD5();
 21     RestTemplate restTemplate = new RestTemplate();
 22 
 23     /**
 24      * 微信支付統一下單接口
 25      * 
 26      * @param notifyUrl 支付成功後回調路徑
 27      * @param openId 用戶的 openId
 28      * @param body 商品描述
 29      * @param total 支付金額(單位分)
 30      * @param out_trade_no 訂單唯一訂單號
 31      * @return
 32      */
 33     public String unifiedorder(String notifyUrl, String openId, String body, String total, String out_trade_no) {
 34         WechatPayModel xml = new WechatPayModel();
 35         xml.setAppid(Configure.getAppid());
 36         xml.setMch_id(Configure.getMchid());
 37         xml.setNonce_str(encoder.createNonceStr());
 38         xml.setBody(body);
 39         xml.setOut_trade_no(out_trade_no);
 40         xml.setTotal_fee(total);
 41         xml.setSpbill_create_ip(Configure.getIP());
 42         xml.setNotify_url(notifyUrl);
 43         xml.setTrade_type(Configure.TRADE_TYPE);
 44         xml.setOpenid(openId);
 45         xml.sign(encoder);
 46         return restTemplate.postForObject(Configure.UNIFIEDORDER_API, xml, String.class);
 47     }
 48 
 49     /**
 50      * 調起微信支付
 51      * 
 52      * @param model
 53      * @param res 預支付訂單 字符串
 54      * @param url 微信支付 url
 55      */
 56     public void wechatPay(Model model, String res,String url) {
 57         try {
 58             Map<String, String> start = new HashMap<>();
 59             StringBuilder startSign = new StringBuilder();
 60 
 61             Map<String, String> pay = new HashMap<>();
 62             StringBuilder paySign = new StringBuilder();
 63             XmlMapper xmlMapper = new XmlMapper();
 64             JsonNode node = xmlMapper.readTree(res);
 65             if (StringUtils.equals(node.get("return_code").asText(), Configure.SUCCESS)) {
 66                 // 得到的預支付訂單,重新生成微信支付參數
 67                 String prepay_id = node.get("prepay_id").asText();
 68                 String jsapi_ticket = jsapiTicket();
 69                 // 生成 微信支付 config 參數
 70                 start.put("appId", Configure.getAppid());
 71                 start.put("nonceStr", encoder.createNonceStr());
 72                 start.put("timestamp", encoder.createTimeStamp());
 73                 // 生成 config 簽名
 74                 startSign.append("jsapi_ticket=").append(jsapi_ticket);
 75                 startSign.append("&noncestr=").append(start.get("nonceStr"));
 76                 startSign.append("&timestamp=").append(start.get("timestamp"));
 77                 startSign.append("&url=").append(url);
 78                 start.put("signature", encoder.encode(startSign.toString()));
 79                 
 80                 // config信息驗證後會執行ready方法的參數
 81                 pay.put("signType", Configure.MD5);
 82                 pay.put("packageStr", "prepay_id=" + prepay_id);
 83                 // 生成支付簽名
 84                 paySign.append("appId=").append(start.get("appId"));
 85                 paySign.append("&nonceStr=").append(start.get("nonceStr"));
 86                 paySign.append("&package=").append(pay.get("packageStr"));
 87                 paySign.append("&signType=").append(pay.get("signType"));
 88                 paySign.append("&timeStamp=").append(start.get("timestamp"));
 89                 paySign.append("&key=").append(Configure.getKey());
 90                 pay.put("paySign", encoder.encode(paySign.toString()));
 91                 // 將微信支參數放入 model 對象中以便前端使用
 92                 model.addAttribute("start", start);
 93                 model.addAttribute("pay", pay);
 94             }
 95         } catch (Exception e) {
 96             model.addAttribute("wechatMessage", "微信授權失敗!");
 97             e.printStackTrace();
 98         }
 99     }
100 
101     /**
102      * 微信授權,獲取 access_token
103      * 
104      * @return access_token
105      */
106     public String getToken() {
107         if (Configure.checkToken()) {
108             // 聲明 獲取 access_token 路徑
109             StringBuilder tokenBuilder = new StringBuilder();
110             tokenBuilder.append(Configure.TOKEN_API);
111             tokenBuilder.append("&appid=").append(Configure.getAppid());
112             tokenBuilder.append("&secret=").append(Configure.getAppSecret());
113             // 獲取 token
114             Map<?, ?> token = restTemplate.getForObject(tokenBuilder.toString(), Map.class);
115             Configure.setToken((String) token.get("access_token"));
116         }
117         return Configure.getToken();
118     }
119 
120     /**
121      * 獲取微信 JSAPI 支付的臨時票據
122      * 
123      * @return 臨時票據
124      */
125     public String jsapiTicket() {
126         if (Configure.checkJsapiTicket()) {
127             // 聲明 獲取臨時票據路徑
128             StringBuilder ticketBuilder = new StringBuilder();
129             ticketBuilder.append(Configure.TICKET_API);
130             ticketBuilder.append("?access_token=").append(getToken());
131             ticketBuilder.append("&type=jsapi");
132             // 獲取 臨時票據
133             Map<?, ?> jsapiTicket = restTemplate.getForObject(ticketBuilder.toString(), Map.class);
134             Configure.setJsapiTicket((String) jsapiTicket.get("ticket"));
135         }
136         return Configure.getJsapiTicket();
137     }
138 
139     /**
140      * 獲取用的 OPENID
141      * 
142      * @param code 微信認證回調的 code
143      * @return
144      */
145     public String takeOpenId(String code) {
146         // 聲明 獲取OPENID路徑
147         StringBuilder openidBuilder = new StringBuilder();
148         openidBuilder.append(Configure.OPENID_API);
149         openidBuilder.append("?appid=").append(Configure.getAppid());
150         openidBuilder.append("&secret=").append(Configure.getAppSecret());
151         openidBuilder.append("&code=").append(code);
152         openidBuilder.append("&grant_type=authorization_code");
153         // 獲取 OPENID
154         String res = restTemplate.getForObject(openidBuilder.toString(), String.class);
155         Map<?, ?> map = JSONArray.parseObject(res, Map.class);
156         return String.valueOf(map.get("openid"));
157     }
158 }

 

10. WechatPayController.java 頁面

 1 package com.kzb.website.web.wechat;
 2 
 3 import java.util.Date;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 
 7 import org.apache.commons.lang3.StringUtils;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.stereotype.Controller;
10 import org.springframework.ui.Model;
11 import org.springframework.web.bind.annotation.RequestMapping;
12 import org.springframework.web.bind.annotation.RequestMethod;
13 import org.springframework.web.bind.annotation.RequestParam;
14 import org.springframework.web.bind.annotation.ResponseBody;
15 
16 import com.kzb.website.core.wechat.common.Configure;
17 import com.kzb.website.core.wechat.common.WechatNotify;
18 import com.kzb.website.core.wechat.common.WechatUtil;
19 
20 @RequestMapping("wxpay")
21 @Controller
22 public class WechatPayController {
23 
24     @Autowired
25     private PayService payService;
26 
27     @RequestMapping("payment.htm")
28     public String payment(@RequestParam(required = false) String code, Model model, HttpServletRequest request){
29         String openId = payService.takeOpenId(code);
30         if (StringUtils.isEmpty(openId)) {
31             return "pay/wxpay_error";
32         }
33         String notify = "http://www.xxxxxx.net/wxpay/notify.htm";
34         String body = "商品支付內容";
35         String total = "1"; // 單位分
36         String out_trade_no = new Date().getTime() + "";
37         
38         String res = payService.unifiedorder(notify, openId, body, total, out_trade_no);
39 
40         String url = "http://www.xxxxxx.net/wxpay/payment.htm";
41         payService.wechatPay(model,res,url);
42         return "pay/wxpay";
43     }
44 
45     /**
46      * 微信支付成功後的回調函數
47      * 
48      * @param request
49      * @return
50      */
51     @RequestMapping(value="notify.htm",method=RequestMethod.POST)
52     @ResponseBody
53     public String wechatNotify(HttpServletRequest request){
54         // 從 request 對象中獲取 WechatNotify 對象
55         WechatNotify notify = WechatUtil.getNotifyBean(request);
56         // 如果 notify 對象不為空 並且 result_code 和 return_code 都為 'SUCCESS' 則表示支付成功
57         if (notify != null
58                 && StringUtils.equals(notify.getResult_code(), Configure.SUCCESS)
59                 && StringUtils.equals(notify.getReturn_code(), Configure.SUCCESS)) {
60 
61             return Configure.NOTIFY_SUCCESS;
62         }
63         return Configure.NOTIFY_FAIL;
64     }
65 }

 

現在就只需要放入服務器測試啦,趕快行動起來,試試吧

下面還有幾篇來說說微信支付中遇到的那些 操蛋 的問題吧

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved