最近項目需要微信支付,然后看了下微信公眾號支付,,雖然不難,但是細節還是需要注意的,用了大半天時間寫了個demo,并且完整的測試了一下支付流程,下面分享一下微信公眾號支付的經驗。
一、配置公眾號微信支付
需要我們配置微信公眾號支付地址和測試白名單。
比如:支付JS頁面的地址為 http://www.xxx.com/shop/pay/
那此處配置www.xxx.com/shop/pay/
二、開發流程
借用微信公眾號支付api(地址 http://pay.weixin.qq.com/wiki/doc/api/index.PHP?chapter=7_4),我們需要開發的為紅色標記出的。如下:
三、向微信服務器端下訂單
調用統一下單接口,這樣就能獲取微信支付的prepay_id(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1)。
在調用該接口前有幾個字段是H5支付必須填寫的openid
3.1 獲取openid
可以通過網頁授權形式(http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)
在微信中發送如下鏈接
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=要跳轉的下訂單的url&response_type=code&scope=snsapi_base&state=123#wechat_redirect
3.2 下訂單獲取prepay_id
代碼如下,實際上是通過post發送一個xml 文件,獲取微信服務器端發送過來的prepay_id。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
import java.io.ByteArrayInputStream; import javaioIOException; import javaioInputStream; import javaioUnsupportedEncodingException; import javautilDate; import javautilHashMap; import javautilIterator; import javautilMap; import javautilMapEntry; import javautilRandom; import javaxservlethttpHttpServletRequest; import javaxservlethttpHttpServletResponse; import orgapachecommonscodecdigestDigestUtils; import orgspringframeworkstereotypeController; import orgspringframeworkwebbindannotationRequestMapping; import orgxmlpullvXmlPullParser; import orgxmlpullvXmlPullParserException; import orgxmlpullvXmlPullParserFactory; import comfasterxmljacksondatabindJsonNode; import comgsonoauthOauth; import comgsonoauthPay; import comgsonutilHttpKit; import comsyutilDatetimeUtil; import comsyutilJsonUtil; @Controller @RequestMapping ( "/pay" ) public class WXPayController { @RequestMapping (value = "wxprepaydo" ) public void jspay(HttpServletRequest request, HttpServletResponse response, String callback) throws Exception { // 獲取openid String openId = SessionUtilgetAtt(request, "openId" ); if (openId == null ) { openId = getUserOpenId(request); } String appid = "wx16691fcb0523c1a4" ; String paternerKey = "ININGFENG1234567fdfwfdfd1ss234567" ; String out_trade_no = getTradeNo(); Map<String, String> paraMap = new HashMap<String, String>(); paraMapput( "appid" , appid); paraMapput( "attach" , "測試" ); paraMapput( "body" , "測試購買支付" ); paraMapput( "mch_id" , "10283271" ); paraMapput( "nonce_str" , create_nonce_str()); paraMapput( "openid" , openId); paraMapput( "out_trade_no" , out_trade_no); paraMapput( "spbill_create_ip" , getAddrIp(request)); paraMapput( "total_fee" , "1" ); paraMapput( "trade_type" , "JSAPI" ); paraMapput( "notify_url" , "http://wwwxxxco/bank/page/wxnotify" ); String sign = getSign(paraMap, paternerKey); paraMapput( "sign" , sign); // 統一下單 https://apimchweixinqqcom/pay/unifiedorder String url = "https://apimchweixinqqcom/pay/unifiedorder" ; String xml = ArrayToXml(paraMap); String xmlStr = HttpKitpost(url, xml); // 預付商品id String prepay_id = "" ; if (xmlStrindexOf( "SUCCESS" ) != - 1 ) { Map<String, String> map = doXMLParse(xmlStr); prepay_id = (String) mapget( "prepay_id" ); } Map<String, String> payMap = new HashMap<String, String>(); payMapput( "appId" , appid); payMapput( "timeStamp" , create_timestamp()); payMapput( "nonceStr" , create_nonce_str()); payMapput( "signType" , "MD5" ); payMapput( "package" , "prepay_id=" + prepay_id); String paySign = getSign(payMap, paternerKey); payMapput( "pg" , prepay_id); payMapput( "paySign" , paySign); WebUtilresponse(response, WebUtilpackJsonp(callback, JsonUtilwarpJsonNodeResponse(JsonUtilobjectToJsonNode(payMap))toString())); } /** * map轉成xml * * @param arr * @return */ public String ArrayToXml(Map<String, String> arr) { String xml = "<xml>" ; Iterator<Entry<String, String>> iter = arrentrySet()iterator(); while (iterhasNext()) { Entry<String, String> entry = iternext(); String key = entrygetKey(); String val = entrygetValue(); xml += "<" + key + ">" + val + "</" + key + ">" ; } xml += "</xml>" ; return xml; } // 獲取openId private String getUserOpenId(HttpServletRequest request) throws Exception { String code = requestgetParameter( "code" ); if (code == null ) { String openId = requestgetParameter( "openId" ); return openId; } Oauth o = new Oauth(); String token = ogetToken(code); JsonNode node = JsonUtilStringToJsonNode(token); String openId = nodeget( "openid" )asText(); return openId; } private String create_nonce_str() { String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ; String res = "" ; for ( int i = 0 ; i < 16 ; i++) { Random rd = new Random(); res += charscharAt(rdnextInt(charslength() - 1 )); } return res; } private String getAddrIp(HttpServletRequest request){ return requestgetRemoteAddr(); } private String create_timestamp() { return LongtoString(SystemcurrentTimeMillis() / 1000 ); } private String getTradeNo(){ String timestamp = DatetimeUtilformatDate( new Date(), DatetimeUtilDATETIME_PATTERN); return "HZNO" + timestamp; } private String getSign(Map<String, String> params, String paternerKey ) throws UnsupportedEncodingException { String string1 = PaycreateSign(params, false ); String stringSignTemp = string1 + "&key=" + paternerKey; String signValue = DigestUtilsmd5Hex(stringSignTemp)toUpperCase(); return signValue; } private Map<String, String> doXMLParse(String xml) throws XmlPullParserException, IOException { InputStream inputStream = new ByteArrayInputStream(xmlgetBytes()); Map<String, String> map = null ; XmlPullParser pullParser = XmlPullParserFactorynewInstance() newPullParser(); pullParsersetInput(inputStream, "UTF-8" ); // 為xml設置要解析的xml數據 int eventType = pullParsergetEventType(); while (eventType != XmlPullParserEND_DOCUMENT) { switch (eventType) { case XmlPullParserSTART_DOCUMENT: map = new HashMap<String, String>(); break ; case XmlPullParserSTART_TAG: String key = pullParsergetName(); if (keyequals( "xml" )) break ; String value = pullParsernextText(); mapput(key, value); break ; case XmlPullParserEND_TAG: break ; } eventType = pullParsernext(); } return map; } } |
四、H5支付
H5支付其實很簡單,只需要調用微信內嵌瀏覽器的js方法就行(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=7_7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
<%@ page language= "java" contentType= "text/html; charset=UTF-8" pageEncoding= "UTF-8" %> <%@ taglib prefix= "spring" uri= "http://wwwspringframeworkorg/tags" %> <% String path = requestgetContextPath(); String basePath = requestgetScheme() + "://" + requestgetServerName() + ":" + requestgetServerPort() + path + "/" ; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 01 Transitional//EN" "http://wwwworg/TR/html4/loosedtd" > <html> <head> <meta charset= "utf-8" /> <meta name= "viewport" content= "width=device-width, initial-scale=0, maximum-scale=0, user-scalable=0" /> <meta name= "apple-mobile-web-app-capable" content= "yes" /> <meta name= "apple-mobile-web-app-status-bar-style" content= "black" /> <meta name= "format-detection" content= "telephone=no" /> <title>測試支付</title> <link href= "/css/csscss?v=0" rel= "stylesheet" type= "text/css" > </head> <body> <div class = "index_box" > <div class = "apply_name" >微信js支付測試</div> <div class = "branch_con" > <ul> <li><span class = "name" >測試支付信息</span></li> </ul> <p class = "cz_btn" ><a href= "javascript:pay();" class = "btn_1" >立即支付</a></p> </div> </div> <script type= "text/javascript" src= "/js/zeptominjs" ></script> <script type= "text/javascript" src= "/js/commonjs" ></script> <script type= "text/javascript" > var appId = urlparameter( "appId" ); var timeStamp = urlparameter( "timeStamp" ); var nonceStr = urlparameter( "nonceStr" ); var pg = urlparameter( "pg" ); var signType = urlparameter( "signType" ); var paySign = urlparameter( "paySign" ); function onBridgeReady(){ WeixinJSBridgeinvoke( 'getBrandWCPayRequest' , { "appId" : appId, //公眾號名稱,由商戶傳入 "timeStamp" : timeStamp, //時間戳,自1970年以來的秒數 "nonceStr" : nonceStr, //隨機串 "package" : "prepay_id=" + pg, "paySign" : paySign //微信簽名 }, function(res){ if (reserr_msg == "get_brand_wcpay_request:ok" ) { alert( "支付成功" ); } // 使用以上方式判斷前端返回,微信團隊鄭重提示:reserr_msg將在用戶支付成功后返回 ok,但并不保證它絕對可靠。 } ); } function pay(){ if (typeof WeixinJSBridge == "undefined" ){ if ( documentaddEventListener ){ documentaddEventListener( 'WeixinJSBridgeReady' , onBridgeReady, false ); } else if (documentattachEvent){ documentattachEvent( 'WeixinJSBridgeReady' , onBridgeReady); documentattachEvent( 'onWeixinJSBridgeReady' , onBridgeReady); } } else { onBridgeReady(); } } </script> </body> </html> |
效果如下
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/u014351782/article/details/52186932