微信支付(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("¬ify_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("×tamp=").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 }
現在就只需要放入服務器測試啦,趕快行動起來,試試吧
下面還有幾篇來說說微信支付中遇到的那些 操蛋 的問題吧